]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/pdns_recursor.cc
poll events are bitmasks, not values
[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>
f097141b 29#ifdef HAVE_BOOST_CONTAINER_FLAT_SET_HPP
b47026fd 30#include <boost/container/flat_set.hpp>
f097141b 31#endif
2470b36e 32#include "ws-recursor.hh"
c390b2da 33#include <thread>
519f5484 34#include "threadname.hh"
3ea54bf0 35#include "recpacketcache.hh"
3ddb9247 36#include "utility.hh"
51e2144e 37#include "dns_random.hh"
d1b28475
KM
38#ifdef HAVE_LIBSODIUM
39#include <sodium.h>
40#endif
3afde9b2 41#include "opensslsigners.hh"
288f4aa9
BH
42#include <iostream>
43#include <errno.h>
81859ba5 44#include <boost/static_assert.hpp>
288f4aa9
BH
45#include <map>
46#include <set>
97bb160b 47#include "recursor_cache.hh"
38c9ceaa 48#include "cachecleaner.hh"
288f4aa9 49#include <stdio.h>
c75a6a9e 50#include <signal.h>
288f4aa9 51#include <stdlib.h>
bb4bdbaf 52#include "misc.hh"
288f4aa9
BH
53#include "mtasker.hh"
54#include <utility>
288f4aa9
BH
55#include "arguments.hh"
56#include "syncres.hh"
88def049
BH
57#include <fcntl.h>
58#include <fstream>
3e61e7f7 59#include "sortlist.hh"
5c633640
BH
60#include "sstuff.hh"
61#include <boost/tuple/tuple.hpp>
62#include <boost/tuple/tuple_comparison.hpp>
72df400f 63#include <boost/shared_array.hpp>
7f1fa77d 64#include <boost/function.hpp>
5605c067 65#include <boost/algorithm/string.hpp>
8f7473d7 66#ifdef MALLOC_TRACE
67#include "malloctrace.hh"
68#endif
40a3dd64 69#include <netinet/tcp.h>
f12666f2 70#include "capabilities.hh"
ea634573
BH
71#include "dnsparser.hh"
72#include "dnswriter.hh"
73#include "dnsrecords.hh"
f814d7c8 74#include "zoneparser-tng.hh"
1d5b3ce6 75#include "rec_channel.hh"
aaacf7f2 76#include "logger.hh"
c8ddb7c2 77#include "iputils.hh"
09e6702a 78#include "mplexer.hh"
c038218b 79#include "config.h"
808c5ef7 80#include "lua-recursor4.hh"
ba1a571d 81#include "version.hh"
79332bff 82#include "responsestats.hh"
d67620e4 83#include "secpoll-recursor.hh"
c5c066bf 84#include "dnsname.hh"
644dd1da 85#include "filterpo.hh"
86#include "rpzloader.hh"
b3f0ed10 87#include "validate-recursor.hh"
f3c18728 88#include "rec-lua-conf.hh"
5c3b5e7f 89#include "ednsoptions.hh"
85c7ca75 90#include "gettime.hh"
d6f3fcfa 91#include "pubsuffix.hh"
af1377b7
NC
92#ifdef NOD_ENABLED
93#include "nod.hh"
94#endif /* NOD_ENABLED */
f3c18728 95
d9d3f9c1 96#include "rec-protobuf.hh"
d705aad9 97#include "rec-snmp.hh"
aa7929a3 98
6b6720de
PL
99#ifdef HAVE_SYSTEMD
100#include <systemd/sd-daemon.h>
101#endif
102
d187038c
RG
103#include "namespaces.hh"
104
d61aa945
RG
105#ifdef HAVE_PROTOBUF
106#include "uuid-utils.hh"
107#endif
108
5cc8371b
RG
109#include "xpf.hh"
110
d187038c
RG
111typedef map<ComboAddress, uint32_t, ComboAddress::addressOnlyLessThan> tcpClientCounts_t;
112
f26bf547 113static thread_local std::shared_ptr<RecursorLua4> t_pdl;
b243ca3b 114static thread_local unsigned int t_id = 0;
f26bf547
RG
115static thread_local std::shared_ptr<Regex> t_traceRegex;
116static thread_local std::unique_ptr<tcpClientCounts_t> t_tcpClientCounts;
63341e8d 117#ifdef HAVE_PROTOBUF
3fe06137 118static thread_local std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>> t_protobufServers{nullptr};
b773359c 119static thread_local uint64_t t_protobufServersGeneration;
3fe06137 120static thread_local std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>> t_outgoingProtobufServers{nullptr};
b773359c 121static thread_local uint64_t t_outgoingProtobufServersGeneration;
63341e8d 122#endif /* HAVE_PROTOBUF */
f26bf547
RG
123
124thread_local std::unique_ptr<MT_t> MT; // the big MTasker
125thread_local std::unique_ptr<MemRecursorCache> t_RC;
126thread_local std::unique_ptr<RecursorPacketCache> t_packetCache;
3337c2f7 127thread_local FDMultiplexer* t_fdm{nullptr};
be9078b3 128thread_local std::unique_ptr<addrringbuf_t> t_remotes, t_servfailremotes, t_largeanswerremotes, t_bogusremotes;
66f2e6ad 129thread_local std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t> > > t_queryring, t_servfailqueryring, t_bogusqueryring;
f26bf547 130thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
af1377b7
NC
131#ifdef NOD_ENABLED
132thread_local std::shared_ptr<nod::NODDB> t_nodDBp;
41c542ec 133thread_local std::shared_ptr<nod::UniqueResponseDB> t_udrDBp;
af1377b7 134#endif /* NOD_ENABLED */
d187038c 135__thread struct timeval g_now; // timestamp, updated (too) frequently
d7dae798 136
b243ca3b
RG
137typedef vector<pair<int, function< void(int, any&) > > > deferredAdd_t;
138
d7dae798 139// for communicating with our threads
b243ca3b
RG
140// effectively readonly after startup
141struct RecThreadInfo
142{
143 struct ThreadPipeSet
144 {
145 int writeToThread{-1};
146 int readToThread{-1};
147 int writeFromThread{-1};
148 int readFromThread{-1};
149 int writeQueriesToThread{-1}; // this one is non-blocking
150 int readQueriesToThread{-1};
151 };
152
adb6cd72 153 /* FD corresponding to TCP sockets this thread is listening
c47f201b 154 on.
adb6cd72
RG
155 These FDs are also in deferredAdds when we have one
156 socket per listener, and in g_deferredAdds instead. */
157 std::set<int> tcpSockets;
b243ca3b
RG
158 /* FD corresponding to listening sockets if we have one socket per
159 listener (with reuseport), otherwise all listeners share the
160 same FD and g_deferredAdds is then used instead */
161 deferredAdd_t deferredAdds;
162 struct ThreadPipeSet pipes;
163 std::thread thread;
144040be
RG
164 MT_t* mt{nullptr};
165 uint64_t numberOfDistributedQueries{0};
b243ca3b
RG
166 /* handle the web server, carbon, statistics and the control channel */
167 bool isHandler{false};
168 /* accept incoming queries (and distributes them to the workers if pdns-distributes-queries is set) */
169 bool isListener{false};
170 /* process queries */
171 bool isWorker{false};
49a699c4 172};
810ff705 173
b243ca3b
RG
174/* first we have the handler thread, t_id == 0 (some other
175 helper threads like SNMP might have t_id == 0 as well)
176 then the distributor threads if any
177 and finally the workers */
178static std::vector<RecThreadInfo> s_threadInfos;
179/* without reuseport, all listeners share the same sockets */
180static deferredAdd_t g_deferredAdds;
faf580f5 181
d187038c
RG
182typedef vector<int> tcpListenSockets_t;
183typedef map<int, ComboAddress> listenSocketsAddresses_t; // is shared across all threads right now
3ea54bf0 184
d187038c 185static const ComboAddress g_local4("0.0.0.0"), g_local6("::");
d187038c 186static listenSocketsAddresses_t g_listenSocketsAddresses; // is shared across all threads right now
d187038c
RG
187static set<int> g_fromtosockets; // listen sockets that use 'sendfromto()' mechanism
188static vector<ComboAddress> g_localQueryAddresses4, g_localQueryAddresses6;
189static AtomicCounter counter;
9065eb05 190static std::shared_ptr<SyncRes::domainmap_t> g_initialDomainMap; // new threads needs this to be setup
f26bf547 191static std::shared_ptr<NetmaskGroup> g_initialAllowFrom; // new thread needs to be setup with this
5cc8371b 192static NetmaskGroup g_XPFAcl;
d187038c 193static size_t g_tcpMaxQueriesPerConn;
a5886e6a 194static size_t s_maxUDPQueriesPerRound;
d187038c
RG
195static uint64_t g_latencyStatSize;
196static uint32_t g_disthashseed;
197static unsigned int g_maxTCPPerClient;
d187038c 198static unsigned int g_maxMThreads;
b243ca3b 199static unsigned int g_numDistributorThreads;
d187038c
RG
200static unsigned int g_numWorkerThreads;
201static int g_tcpTimeout;
202static uint16_t g_udpTruncationThreshold;
59cb4a79 203static uint16_t g_xpfRRCode{0};
d187038c
RG
204static std::atomic<bool> statsWanted;
205static std::atomic<bool> g_quiet;
206static bool g_logCommonErrors;
207static bool g_anyToTcp;
b243ca3b 208static bool g_weDistributeQueries; // if true, 1 or more threads listen on the incoming query sockets and distribute them to workers
810ff705 209static bool g_reusePort{false};
00b8cadc 210static bool g_gettagNeedsEDNSOptions{false};
0ec489bf 211static time_t g_statisticsInterval;
9065eb05 212static bool g_useIncomingECS;
a6f7f5fe 213std::atomic<uint32_t> g_maxCacheEntries, g_maxPacketCacheEntries;
af1377b7
NC
214#ifdef NOD_ENABLED
215static bool g_nodEnabled;
216static DNSName g_nodLookupDomain;
217static bool g_nodLog;
218static SuffixMatchNode g_nodDomainWL;
ca2526f5 219static std::string g_nod_pbtag;
41c542ec
NC
220static bool g_udrEnabled;
221static bool g_udrLog;
ca2526f5 222static std::string g_udr_pbtag;
af1377b7 223#endif /* NOD_ENABLED */
f097141b 224#ifdef HAVE_BOOST_CONTAINER_FLAT_SET_HPP
bf6f28ca 225static boost::container::flat_set<uint16_t> s_avoidUdpSourcePorts;
f097141b
CHB
226#else
227static std::set<uint16_t> s_avoidUdpSourcePorts;
228#endif
bf6f28ca
CHB
229static uint16_t s_minUdpSourcePort;
230static uint16_t s_maxUdpSourcePort;
144040be 231static double s_balancingFactor;
49a699c4 232
b243ca3b 233RecursorControlChannel s_rcc; // only active in the handler thread
d187038c 234RecursorStats g_stats;
2d733c0f 235string s_programname="pdns_recursor";
d187038c 236string s_pidfname;
c1c29961 237bool g_lowercaseOutgoing;
bf19ccfd 238unsigned int g_networkTimeoutMsec;
d187038c
RG
239unsigned int g_numThreads;
240uint16_t g_outgoingEDNSBufsize;
98d36505 241bool g_logRPZChanges{false};
c3828c03 242
12cd44ee 243#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 244#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 245// Bad Nets taken from both:
3ddb9247 246// http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
12cd44ee 247// and
248// http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
249// where such a network may not be considered a valid destination
250#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"
251#define DONT_QUERY LOCAL_NETS ", " BAD_NETS
49a699c4 252
d7dae798 253//! used to send information to a newborn mthread
ea634573 254struct DNSComboWriter {
08b02366 255 DNSComboWriter(const std::string& query, const struct timeval& now): d_mdp(true, query), d_now(now), d_query(query)
2749c3fe
RG
256 {
257 }
5cc8371b 258
08b02366 259 DNSComboWriter(const std::string& query, const struct timeval& now, std::vector<std::string>&& policyTags, LuaContext::LuaObject&& data): d_mdp(true, query), d_now(now), d_query(query), d_policyTags(std::move(policyTags)), d_data(std::move(data))
5164bac3
RG
260 {
261 }
262
5cc8371b
RG
263 void setRemote(const ComboAddress& sa)
264 {
265 d_remote=sa;
266 }
267
268 void setSource(const ComboAddress& sa)
ea634573 269 {
5cc8371b 270 d_source=sa;
ea634573
BH
271 }
272
b71b60ee 273 void setLocal(const ComboAddress& sa)
274 {
275 d_local=sa;
276 }
277
5cc8371b
RG
278 void setDestination(const ComboAddress& sa)
279 {
280 d_destination=sa;
281 }
b71b60ee 282
ea634573
BH
283 void setSocket(int sock)
284 {
285 d_socket=sock;
286 }
a1754c6a
BH
287
288 string getRemote() const
289 {
5cc8371b
RG
290 if (d_source == d_remote) {
291 return d_source.toStringWithPort();
292 }
293 return d_source.toStringWithPort() + " (proxied by " + d_remote.toStringWithPort() + ")";
a1754c6a
BH
294 }
295
5cc8371b 296 MOADNSParser d_mdp;
c9e9e5e0 297 struct timeval d_now;
5cc8371b
RG
298 /* Remote client, might differ from d_source
299 in case of XPF, in which case d_source holds
300 the IP of the client and d_remote of the proxy
301 */
302 ComboAddress d_remote;
303 ComboAddress d_source;
304 /* Destination address, might differ from
305 d_destination in case of XPF, in which case
306 d_destination holds the IP of the proxy and
307 d_local holds our own. */
308 ComboAddress d_local;
309 ComboAddress d_destination;
aa7929a3
RG
310#ifdef HAVE_PROTOBUF
311 boost::uuids::uuid d_uuid;
67e31ebe 312 string d_requestorId;
590388d2 313 string d_deviceId;
aa7929a3 314#endif
08b02366 315 std::string d_query;
5164bac3
RG
316 std::vector<std::string> d_policyTags;
317 LuaContext::LuaObject d_data;
b40562da 318 EDNSSubnetOpts d_ednssubnet;
5164bac3 319 shared_ptr<TCPConnection> d_tcpConnection;
ea634573 320 int d_socket;
b673817a 321 unsigned int d_tag{0};
e9f63d47 322 uint32_t d_qhash{0};
70fb28d9 323 uint32_t d_ttlCap{std::numeric_limits<uint32_t>::max()};
08b02366
RG
324 uint16_t d_ecsBegin{0};
325 uint16_t d_ecsEnd{0};
70fb28d9 326 bool d_variable{false};
5164bac3
RG
327 bool d_ecsFound{false};
328 bool d_ecsParsed{false};
329 bool d_tcp;
ea634573
BH
330};
331
06857845
RG
332MT_t* getMT()
333{
334 return MT ? MT.get() : nullptr;
335}
ea634573 336
288f4aa9
BH
337ArgvMap &arg()
338{
339 static ArgvMap theArg;
340 return theArg;
341}
4ef015cd 342
8fb594ba 343unsigned int getRecursorThreadId()
b4015453 344{
30da2030 345 return t_id;
b4015453 346}
09e6702a 347
30ee601a
RG
348int getMTaskerTID()
349{
350 return MT->getTid();
351}
352
b243ca3b
RG
353static bool isDistributorThread()
354{
355 if (t_id == 0) {
356 return false;
357 }
358
359 return g_weDistributeQueries && s_threadInfos.at(t_id).isListener;
360}
361
362static bool isHandlerThread()
363{
364 if (t_id == 0) {
365 return true;
366 }
367
368 return s_threadInfos.at(t_id).isHandler;
369}
370
d187038c 371static void handleTCPClientWritable(int fd, FDMultiplexer::funcparam_t& var);
09e6702a 372
50c81227 373// -1 is error, 0 is timeout, 1 is success
3ddb9247 374int asendtcp(const string& data, Socket* sock)
5c633640
BH
375{
376 PacketID pident;
377 pident.sock=sock;
378 pident.outMSG=data;
3ddb9247 379
bb4bdbaf 380 t_fdm->addWriteFD(sock->getHandle(), handleTCPClientWritable, pident);
50c81227 381 string packet;
5c633640 382
5b0ddd18 383 int ret=MT->waitEvent(pident, &packet, g_networkTimeoutMsec);
23db0a09 384
9170fbaf 385 if(!ret || ret==-1) { // timeout
bb4bdbaf 386 t_fdm->removeWriteFD(sock->getHandle());
5c633640 387 }
50c81227
BH
388 else if(packet.size() !=data.size()) { // main loop tells us what it sent out, or empty in case of an error
389 return -1;
390 }
9170fbaf 391 return ret;
5c633640
BH
392}
393
d187038c 394static void handleTCPClientReadable(int fd, FDMultiplexer::funcparam_t& var);
09e6702a 395
9170fbaf 396// -1 is error, 0 is timeout, 1 is success
a683e8bd 397int arecvtcp(string& data, size_t len, Socket* sock, bool incompleteOkay)
288f4aa9 398{
50c81227 399 data.clear();
5c633640
BH
400 PacketID pident;
401 pident.sock=sock;
402 pident.inNeeded=len;
825fa717 403 pident.inIncompleteOkay=incompleteOkay;
bb4bdbaf 404 t_fdm->addReadFD(sock->getHandle(), handleTCPClientReadable, pident);
5c633640 405
bb4bdbaf 406 int ret=MT->waitEvent(pident,&data, g_networkTimeoutMsec);
9170fbaf 407 if(!ret || ret==-1) { // timeout
bb4bdbaf 408 t_fdm->removeReadFD(sock->getHandle());
288f4aa9 409 }
50c81227
BH
410 else if(data.empty()) {// error, EOF or other
411 return -1;
412 }
413
9170fbaf 414 return ret;
288f4aa9
BH
415}
416
d187038c 417static void handleGenUDPQueryResponse(int fd, FDMultiplexer::funcparam_t& var)
4465e941 418{
fba1e944 419 PacketID pident=*any_cast<PacketID>(&var);
4465e941 420 char resp[512];
7c77ce63
RG
421 ComboAddress fromaddr;
422 socklen_t addrlen=sizeof(fromaddr);
423
424 ssize_t ret=recvfrom(fd, resp, sizeof(resp), 0, (sockaddr *)&fromaddr, &addrlen);
425 if (fromaddr != pident.remote) {
e6a9dde5 426 g_log<<Logger::Notice<<"Response received from the wrong remote host ("<<fromaddr.toStringWithPort()<<" instead of "<<pident.remote.toStringWithPort()<<"), discarding"<<endl;
7c77ce63
RG
427
428 }
429
4465e941 430 t_fdm->removeReadFD(fd);
431 if(ret >= 0) {
a683e8bd 432 string data(resp, (size_t) ret);
fba1e944 433 MT->sendEvent(pident, &data);
4465e941 434 }
435 else {
fba1e944 436 string empty;
437 MT->sendEvent(pident, &empty);
438 // cerr<<"Had some kind of error: "<<ret<<", "<<strerror(errno)<<endl;
4465e941 439 }
440}
fba1e944 441string GenUDPQueryResponse(const ComboAddress& dest, const string& query)
4465e941 442{
4465e941 443 Socket s(dest.sin4.sin_family, SOCK_DGRAM);
444 s.setNonBlocking();
445 ComboAddress local = getQueryLocalAddress(dest.sin4.sin_family, 0);
446
447 s.bind(local);
448 s.connect(dest);
4465e941 449 s.send(query);
450
451 PacketID pident;
452 pident.sock=&s;
7c77ce63 453 pident.remote=dest;
4465e941 454 pident.type=0;
fba1e944 455 t_fdm->addReadFD(s.getHandle(), handleGenUDPQueryResponse, pident);
4465e941 456
457 string data;
fba1e944 458
4465e941 459 int ret=MT->waitEvent(pident,&data, g_networkTimeoutMsec);
fba1e944 460
4465e941 461 if(!ret || ret==-1) { // timeout
4465e941 462 t_fdm->removeReadFD(s.getHandle());
463 }
464 else if(data.empty()) {// error, EOF or other
fba1e944 465 // we could special case this
4465e941 466 return data;
467 }
4465e941 468 return data;
469}
470
d7dae798 471//! pick a random query local address
1652a63e 472ComboAddress getQueryLocalAddress(int family, uint16_t port)
5a38281c 473{
1652a63e 474 ComboAddress ret;
5a38281c 475 if(family==AF_INET) {
3ddb9247 476 if(g_localQueryAddresses4.empty())
1652a63e 477 ret = g_local4;
3ddb9247 478 else
1652a63e
BH
479 ret = g_localQueryAddresses4[dns_random(g_localQueryAddresses4.size())];
480 ret.sin4.sin_port = htons(port);
5a38281c
BH
481 }
482 else {
483 if(g_localQueryAddresses6.empty())
1652a63e
BH
484 ret = g_local6;
485 else
486 ret = g_localQueryAddresses6[dns_random(g_localQueryAddresses6.size())];
3ddb9247 487
1652a63e 488 ret.sin6.sin6_port = htons(port);
5a38281c 489 }
1652a63e 490 return ret;
5a38281c 491}
4ef015cd 492
d187038c 493static void handleUDPServerResponse(int fd, FDMultiplexer::funcparam_t&);
09e6702a 494
d187038c 495static void setSocketBuffer(int fd, int optname, uint32_t size)
d7dae798
BH
496{
497 uint32_t psize=0;
498 socklen_t len=sizeof(psize);
3ddb9247 499
d7dae798 500 if(!getsockopt(fd, SOL_SOCKET, optname, (char*)&psize, &len) && psize > size) {
e6a9dde5 501 g_log<<Logger::Error<<"Not decreasing socket buffer size from "<<psize<<" to "<<size<<endl;
3ddb9247 502 return;
d7dae798
BH
503 }
504
505 if (setsockopt(fd, SOL_SOCKET, optname, (char*)&size, sizeof(size)) < 0 )
e6a9dde5 506 g_log<<Logger::Error<<"Unable to raise socket buffer size to "<<size<<": "<<strerror(errno)<<endl;
d7dae798
BH
507}
508
509
510static void setSocketReceiveBuffer(int fd, uint32_t size)
511{
512 setSocketBuffer(fd, SO_RCVBUF, size);
513}
514
515static void setSocketSendBuffer(int fd, uint32_t size)
516{
517 setSocketBuffer(fd, SO_SNDBUF, size);
518}
519
520
4ef015cd
BH
521// you can ask this class for a UDP socket to send a query from
522// this socket is not yours, don't even think about deleting it
523// but after you call 'returnSocket' on it, don't assume anything anymore
524class UDPClientSocks
525{
4ef015cd 526 unsigned int d_numsocks;
4ef015cd 527public:
e2642526 528 UDPClientSocks() : d_numsocks(0)
4ef015cd
BH
529 {
530 }
531
996c89cc 532 typedef set<int> socks_t;
4ef015cd
BH
533 socks_t d_socks;
534
2ee280cf 535 // returning -2 means: temporary OS error (ie, out of files), -1 means error related to remote
d8f6d49f 536 int getSocket(const ComboAddress& toaddr, int* fd)
4ef015cd 537 {
d8f6d49f
BH
538 *fd=makeClientSocket(toaddr.sin4.sin_family);
539 if(*fd < 0) // temporary error - receive exception otherwise
2ee280cf 540 return -2;
d8f6d49f
BH
541
542 if(connect(*fd, (struct sockaddr*)(&toaddr), toaddr.getSocklen()) < 0) {
543 int err = errno;
41ff43f8 544 // returnSocket(*fd);
a7b68ae7
RG
545 try {
546 closesocket(*fd);
547 }
548 catch(const PDNSException& e) {
e6a9dde5 549 g_log<<Logger::Error<<"Error closing UDP socket after connect() failed: "<<e.reason<<endl;
a7b68ae7
RG
550 }
551
d8f6d49f 552 if(err==ENETUNREACH) // Seth "My Interfaces Are Like A Yo Yo" Arnold special
4957a608 553 return -2;
998a4334 554 return -1;
d8f6d49f 555 }
998a4334 556
d8f6d49f 557 d_socks.insert(*fd);
998a4334 558 d_numsocks++;
d8f6d49f 559 return 0;
4ef015cd
BH
560 }
561
095c3045
BH
562 void returnSocket(int fd)
563 {
564 socks_t::iterator i=d_socks.find(fd);
34801ab1 565 if(i==d_socks.end()) {
335da0ba 566 throw PDNSException("Trying to return a socket (fd="+std::to_string(fd)+") not in the pool");
34801ab1 567 }
bb4bdbaf 568 returnSocketLocked(i);
095c3045
BH
569 }
570
4ef015cd 571 // return a socket to the pool, or simply erase it
bb4bdbaf 572 void returnSocketLocked(socks_t::iterator& i)
4ef015cd 573 {
600fc20b 574 if(i==d_socks.end()) {
3f81d239 575 throw PDNSException("Trying to return a socket not in the pool");
600fc20b 576 }
80baf329 577 try {
bb4bdbaf 578 t_fdm->removeReadFD(*i);
80baf329
BH
579 }
580 catch(FDMultiplexerException& e) {
bb4bdbaf 581 // we sometimes return a socket that has not yet been assigned to t_fdm
80baf329 582 }
a7b68ae7
RG
583 try {
584 closesocket(*i);
585 }
586 catch(const PDNSException& e) {
e6a9dde5 587 g_log<<Logger::Error<<"Error closing returned UDP socket: "<<e.reason<<endl;
a7b68ae7 588 }
3ddb9247 589
998a4334
BH
590 d_socks.erase(i++);
591 --d_numsocks;
4ef015cd 592 }
d8f6d49f
BH
593
594 // returns -1 for errors which might go away, throws for ones that won't
bb4bdbaf 595 static int makeClientSocket(int family)
d8f6d49f 596 {
a683e8bd 597 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 598
d8f6d49f
BH
599 if(ret < 0 && errno==EMFILE) // this is not a catastrophic error
600 return ret;
3ddb9247
PD
601
602 if(ret<0)
335da0ba 603 throw PDNSException("Making a socket for resolver (family = "+std::to_string(family)+"): "+stringerror());
36855b53 604
7eb73ffa 605 // setCloseOnExec(ret); // we're not going to exec
5a38281c 606
d8f6d49f 607 int tries=10;
3aa91c3e 608 ComboAddress sin;
d8f6d49f 609 while(--tries) {
1652a63e 610 uint16_t port;
3ddb9247 611
d8f6d49f 612 if(tries==1) // fall back to kernel 'random'
4957a608 613 port = 0;
bf6f28ca
CHB
614 else {
615 do {
616 port = s_minUdpSourcePort + dns_random(s_maxUdpSourcePort - s_minUdpSourcePort + 1);
617 }
618 while (s_avoidUdpSourcePorts.count(port));
619 }
5a38281c 620
3aa91c3e 621 sin=getQueryLocalAddress(family, port); // does htons for us
5a38281c 622
3ddb9247 623 if (::bind(ret, (struct sockaddr *)&sin, sin.getSocklen()) >= 0)
4957a608 624 break;
d8f6d49f
BH
625 }
626 if(!tries)
3aa91c3e 627 throw PDNSException("Resolver binding to local query client socket on "+sin.toString()+": "+stringerror());
3ddb9247 628
29bb743c 629 setReceiveSocketErrors(ret, family);
3897b9e1 630 setNonBlocking(ret);
d8f6d49f
BH
631 return ret;
632 }
49a699c4
BH
633};
634
f26bf547 635static thread_local std::unique_ptr<UDPClientSocks> t_udpclientsocks;
4ef015cd 636
288f4aa9 637/* these two functions are used by LWRes */
34801ab1 638// -2 is OS error, -1 is error that depends on the remote, > 0 is success
a683e8bd 639int asendto(const char *data, size_t len, int flags,
3ddb9247 640 const ComboAddress& toaddr, uint16_t id, const DNSName& domain, uint16_t qtype, int* fd)
288f4aa9 641{
34801ab1
BH
642
643 PacketID pident;
787e5eab
BH
644 pident.domain = domain;
645 pident.remote = toaddr;
646 pident.type = qtype;
34801ab1
BH
647
648 // see if there is an existing outstanding request we can chain on to, using partial equivalence function
649 pair<MT_t::waiters_t::iterator, MT_t::waiters_t::iterator> chain=MT->d_waiters.equal_range(pident, PacketIDBirthdayCompare());
650
651 for(; chain.first != chain.second; chain.first++) {
652 if(chain.first->key.fd > -1) { // don't chain onto existing chained waiter!
e27e91a8 653 /*
4665c31e
BH
654 cerr<<"Orig: "<<pident.domain<<", "<<pident.remote.toString()<<", id="<<id<<endl;
655 cerr<<"Had hit: "<< chain.first->key.domain<<", "<<chain.first->key.remote.toString()<<", id="<<chain.first->key.id
4957a608 656 <<", count="<<chain.first->key.chain.size()<<", origfd: "<<chain.first->key.fd<<endl;
e27e91a8 657 */
34801ab1
BH
658 chain.first->key.chain.insert(id); // we can chain
659 *fd=-1; // gets used in waitEvent / sendEvent later on
660 return 1;
661 }
662 }
663
49a699c4 664 int ret=t_udpclientsocks->getSocket(toaddr, fd);
d8f6d49f
BH
665 if(ret < 0)
666 return ret;
34801ab1 667
998a4334
BH
668 pident.fd=*fd;
669 pident.id=id;
3ddb9247 670
bb4bdbaf
BH
671 t_fdm->addReadFD(*fd, handleUDPServerResponse, pident);
672 ret = send(*fd, data, len, 0);
673
5b0ddd18 674 int tmp = errno;
bb4bdbaf 675
7302ed0a 676 if(ret < 0)
49a699c4 677 t_udpclientsocks->returnSocket(*fd);
bb4bdbaf 678
5b0ddd18 679 errno = tmp; // this is for logging purposes only
7302ed0a 680 return ret;
288f4aa9
BH
681}
682
9170fbaf 683// -1 is error, 0 is timeout, 1 is success
f128d20d 684int arecvfrom(std::string& packet, int flags, const ComboAddress& fromaddr, size_t *d_len,
c5c066bf 685 uint16_t id, const DNSName& domain, uint16_t qtype, int fd, struct timeval* now)
288f4aa9 686{
0d5f0a9f 687 static optional<unsigned int> nearMissLimit;
3ddb9247 688 if(!nearMissLimit)
0d5f0a9f
BH
689 nearMissLimit=::arg().asNum("spoof-nearmiss-max");
690
288f4aa9 691 PacketID pident;
4ef015cd 692 pident.fd=fd;
288f4aa9 693 pident.id=id;
0d5f0a9f 694 pident.domain=domain;
787e5eab 695 pident.type = qtype;
996c89cc 696 pident.remote=fromaddr;
b636533b 697
5b0ddd18 698 int ret=MT->waitEvent(pident, &packet, g_networkTimeoutMsec, now);
34801ab1 699
9170fbaf 700 if(ret > 0) {
996c89cc 701 if(packet.empty()) // means "error"
3ddb9247 702 return -1;
998a4334 703
a683e8bd 704 *d_len=packet.size();
f128d20d 705
0d5f0a9f 706 if(*nearMissLimit && pident.nearMisses > *nearMissLimit) {
e6a9dde5 707 g_log<<Logger::Error<<"Too many ("<<pident.nearMisses<<" > "<<*nearMissLimit<<") bogus answers for '"<<domain<<"' from "<<fromaddr.toString()<<", assuming spoof attempt."<<endl;
0d5f0a9f 708 g_stats.spoofCount++;
35ce8576
BH
709 return -1;
710 }
288f4aa9 711 }
09e6702a 712 else {
34801ab1 713 if(fd >= 0)
49a699c4 714 t_udpclientsocks->returnSocket(fd);
09e6702a 715 }
9170fbaf 716 return ret;
288f4aa9
BH
717}
718
88def049
BH
719static void writePid(void)
720{
191f2e47 721 if(!::arg().mustDo("write-pid"))
722 return;
18e7758c 723 ofstream of(s_pidfname.c_str(), std::ios_base::app);
88def049 724 if(of)
705f31ae 725 of<< Utility::getpid() <<endl;
88def049 726 else
e6a9dde5 727 g_log<<Logger::Error<<"Writing pid for "<<Utility::getpid()<<" to "<<s_pidfname<<" failed: "<<strerror(errno)<<endl;
88def049
BH
728}
729
2749c3fe 730TCPConnection::TCPConnection(int fd, const ComboAddress& addr) : data(2, 0), d_remote(addr), d_fd(fd)
3ddb9247
PD
731{
732 ++s_currentConnections;
cd989c87 733 (*t_tcpClientCounts)[d_remote]++;
0e408828 734}
cd989c87
BH
735
736TCPConnection::~TCPConnection()
0e408828 737{
a7b68ae7
RG
738 try {
739 if(closesocket(d_fd) < 0)
e6a9dde5 740 g_log<<Logger::Error<<"Error closing socket for TCPConnection"<<endl;
a7b68ae7
RG
741 }
742 catch(const PDNSException& e) {
e6a9dde5 743 g_log<<Logger::Error<<"Error closing TCPConnection socket: "<<e.reason<<endl;
a7b68ae7
RG
744 }
745
3ddb9247 746 if(t_tcpClientCounts->count(d_remote) && !(*t_tcpClientCounts)[d_remote]--)
cd989c87 747 t_tcpClientCounts->erase(d_remote);
1bc9e6bd 748 --s_currentConnections;
0e408828 749}
0e9d9ce2 750
3ddb9247 751AtomicCounter TCPConnection::s_currentConnections;
d187038c
RG
752
753static void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var);
6dcd28c3 754
92011b8f 755// the idea is, only do things that depend on the *response* here. Incoming accounting is on incoming.
d187038c 756static void updateResponseStats(int res, const ComboAddress& remote, unsigned int packetsize, const DNSName* query, uint16_t qtype)
2cc13433 757{
92011b8f 758 if(packetsize > 1000 && t_largeanswerremotes)
759 t_largeanswerremotes->push_back(remote);
2cc13433
BH
760 switch(res) {
761 case RCode::ServFail:
92011b8f 762 if(t_servfailremotes) {
763 t_servfailremotes->push_back(remote);
5af86fdc 764 if(query && t_servfailqueryring) // packet cache
92011b8f 765 t_servfailqueryring->push_back(make_pair(*query, qtype));
766 }
2cc13433
BH
767 g_stats.servFails++;
768 break;
769 case RCode::NXDomain:
770 g_stats.nxDomains++;
771 break;
772 case RCode::NoError:
773 g_stats.noErrors++;
774 break;
775 }
776}
777
9a864da4 778static string makeLoginfo(const std::unique_ptr<DNSComboWriter>& dc)
a903b39c 779try
780{
5cc8371b 781 return "("+dc->d_mdp.d_qname.toLogString()+"/"+DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)+" from "+(dc->getRemote())+")";
a903b39c 782}
783catch(...)
784{
785 return "Exception making error message for exception";
786}
787
aa7929a3 788#ifdef HAVE_PROTOBUF
b773359c 789static void protobufLogQuery(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 790{
b773359c
RG
791 if (!t_protobufServers) {
792 return;
793 }
794
e1c8a4bb
RG
795 Netmask requestorNM(remote, remote.sin4.sin_family == AF_INET ? maskV4 : maskV6);
796 const ComboAddress& requestor = requestorNM.getMaskedNetwork();
797 RecProtoBufMessage message(DNSProtoBufMessage::Query, uniqueId, &requestor, &local, qname, qtype, qclass, id, tcp, len);
c165308b 798 message.setServerIdentity(SyncRes::s_serverID);
a94bc5d7 799 message.setEDNSSubnet(ednssubnet, ednssubnet.isIpv4() ? maskV4 : maskV6);
67e31ebe 800 message.setRequestorId(requestorId);
590388d2 801 message.setDeviceId(deviceId);
02b47f43 802
02b47f43 803 if (!policyTags.empty()) {
d9d3f9c1 804 message.setPolicyTags(policyTags);
02b47f43 805 }
aa7929a3 806
d9d3f9c1 807// cerr <<message.toDebugString()<<endl;
aa7929a3 808 std::string str;
d9d3f9c1 809 message.serialize(str);
b773359c
RG
810
811 for (auto& server : *t_protobufServers) {
812 server->queueData(str);
813 }
aa7929a3
RG
814}
815
b773359c 816static void protobufLogResponse(const RecProtoBufMessage& message)
aa7929a3 817{
b773359c
RG
818 if (!t_protobufServers) {
819 return;
820 }
821
d9d3f9c1 822// cerr <<message.toDebugString()<<endl;
aa7929a3 823 std::string str;
d9d3f9c1 824 message.serialize(str);
b773359c
RG
825
826 for (auto& server : *t_protobufServers) {
827 server->queueData(str);
828 }
aa7929a3
RG
829}
830#endif
831
53508135
PL
832/**
833 * Chases the CNAME provided by the PolicyCustom RPZ policy.
834 *
835 * @param spoofed: The DNSRecord that was created by the policy, should already be added to ret
836 * @param qtype: The QType of the original query
837 * @param sr: A SyncRes
838 * @param res: An integer that will contain the RCODE of the lookup we do
839 * @param ret: A vector of DNSRecords where the result of the CNAME chase should be appended to
840 */
d187038c 841static void handleRPZCustom(const DNSRecord& spoofed, const QType& qtype, SyncRes& sr, int& res, vector<DNSRecord>& ret)
53508135
PL
842{
843 if (spoofed.d_type == QType::CNAME) {
30ee601a
RG
844 bool oldWantsRPZ = sr.getWantsRPZ();
845 sr.setWantsRPZ(false);
53508135 846 vector<DNSRecord> ans;
6da513b2 847 res = sr.beginResolve(DNSName(spoofed.d_content->getZoneRepresentation()), qtype, QClass::IN, ans);
53508135
PL
848 for (const auto& rec : ans) {
849 if(rec.d_place == DNSResourceRecord::ANSWER) {
850 ret.push_back(rec);
851 }
852 }
853 // Reset the RPZ state of the SyncRes
30ee601a 854 sr.setWantsRPZ(oldWantsRPZ);
53508135
PL
855 }
856}
857
70fb28d9 858static bool addRecordToPacket(DNSPacketWriter& pw, const DNSRecord& rec, uint32_t& minTTL, uint32_t ttlCap, const uint16_t maxAnswerSize)
97c6d7e5 859{
70fb28d9 860 pw.startRecord(rec.d_name, rec.d_type, (rec.d_ttl > ttlCap ? ttlCap : rec.d_ttl), rec.d_class, rec.d_place);
97c6d7e5
RG
861
862 if(rec.d_type != QType::OPT) // their TTL ain't real
863 minTTL = min(minTTL, rec.d_ttl);
864
865 rec.d_content->toPacket(pw);
866 if(pw.size() > static_cast<size_t>(maxAnswerSize)) {
867 pw.rollback();
868 if(rec.d_place != DNSResourceRecord::ADDITIONAL) {
869 pw.getHeader()->tc=1;
870 pw.truncate();
871 }
872 return false;
873 }
874
875 return true;
876}
877
63341e8d 878#ifdef HAVE_PROTOBUF
3fe06137 879static std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>> startProtobufServers(const ProtobufExportConfig& config)
63341e8d 880{
3fe06137 881 auto result = std::make_shared<std::vector<std::unique_ptr<RemoteLogger>>>();
b773359c
RG
882
883 for (const auto& server : config.servers) {
884 try {
da71b63b 885 result->emplace_back(new RemoteLogger(server, config.timeout, 100*config.maxQueuedEntries, config.reconnectWaitTime, config.asyncConnect));
b773359c
RG
886 }
887 catch(const std::exception& e) {
888 g_log<<Logger::Error<<"Error while starting protobuf logger to '"<<server<<": "<<e.what()<<endl;
889 }
890 catch(const PDNSException& e) {
891 g_log<<Logger::Error<<"Error while starting protobuf logger to '"<<server<<": "<<e.reason<<endl;
892 }
63341e8d
RG
893 }
894
895 return result;
896}
897
898static bool checkProtobufExport(LocalStateHolder<LuaConfigItems>& luaconfsLocal)
899{
900 if (!luaconfsLocal->protobufExportConfig.enabled) {
b773359c
RG
901 if (t_protobufServers) {
902 for (auto& server : *t_protobufServers) {
903 server->stop();
904 }
905 t_protobufServers.reset();
63341e8d
RG
906 }
907
908 return false;
909 }
910
911 /* if the server was not running, or if it was running according to a
912 previous configuration */
b773359c
RG
913 if (!t_protobufServers ||
914 t_protobufServersGeneration < luaconfsLocal->generation) {
63341e8d 915
b773359c
RG
916 if (t_protobufServers) {
917 for (auto& server : *t_protobufServers) {
918 server->stop();
919 }
63341e8d 920 }
b773359c 921 t_protobufServers.reset();
63341e8d 922
b773359c
RG
923 t_protobufServers = startProtobufServers(luaconfsLocal->protobufExportConfig);
924 t_protobufServersGeneration = luaconfsLocal->generation;
63341e8d
RG
925 }
926
927 return true;
928}
929
930static bool checkOutgoingProtobufExport(LocalStateHolder<LuaConfigItems>& luaconfsLocal)
931{
932 if (!luaconfsLocal->outgoingProtobufExportConfig.enabled) {
b773359c
RG
933 if (t_outgoingProtobufServers) {
934 for (auto& server : *t_outgoingProtobufServers) {
935 server->stop();
936 }
63341e8d 937 }
b773359c 938 t_outgoingProtobufServers.reset();
63341e8d
RG
939
940 return false;
941 }
942
943 /* if the server was not running, or if it was running according to a
944 previous configuration */
b773359c
RG
945 if (!t_outgoingProtobufServers ||
946 t_outgoingProtobufServersGeneration < luaconfsLocal->generation) {
63341e8d 947
b773359c
RG
948 if (t_outgoingProtobufServers) {
949 for (auto& server : *t_outgoingProtobufServers) {
950 server->stop();
951 }
63341e8d 952 }
b773359c 953 t_outgoingProtobufServers.reset();
63341e8d 954
b773359c
RG
955 t_outgoingProtobufServers = startProtobufServers(luaconfsLocal->outgoingProtobufExportConfig);
956 t_outgoingProtobufServersGeneration = luaconfsLocal->generation;
63341e8d
RG
957 }
958
959 return true;
960}
961#endif /* HAVE_PROTOBUF */
962
af1377b7 963#ifdef NOD_ENABLED
41c542ec 964static bool nodCheckNewDomain(const DNSName& dname)
af1377b7
NC
965{
966 static const QType qt(QType::A);
967 static const uint16_t qc(QClass::IN);
41c542ec 968 bool ret = false;
af1377b7
NC
969 // First check the (sub)domain isn't whitelisted for NOD purposes
970 if (!g_nodDomainWL.check(dname)) {
971 // Now check the NODDB (note this is probablistic so can have FNs/FPs)
972 if (t_nodDBp && t_nodDBp->isNewDomain(dname)) {
973 if (g_nodLog) {
974 // This should probably log to a dedicated log file
975 g_log<<Logger::Notice<<"Newly observed domain nod="<<dname.toLogString()<<endl;
976 }
977 if (!(g_nodLookupDomain.isRoot())) {
978 // Send a DNS A query to <domain>.g_nodLookupDomain
979 DNSName qname = dname;
980 vector<DNSRecord> dummy;
981 qname += g_nodLookupDomain;
982 directResolve(qname, qt, qc, dummy);
983 }
41c542ec 984 ret = true;
af1377b7
NC
985 }
986 }
41c542ec 987 return ret;
af1377b7
NC
988}
989
990static void nodAddDomain(const DNSName& dname)
991{
992 // Don't bother adding domains on the nod whitelist
993 if (!g_nodDomainWL.check(dname)) {
994 if (t_nodDBp) {
995 // This keeps the nod info up to date
996 t_nodDBp->addDomain(dname);
997 }
998 }
999}
41c542ec
NC
1000
1001static bool udrCheckUniqueDNSRecord(const DNSName& dname, uint16_t qtype, const DNSRecord& record)
1002{
1003 bool ret = false;
1004 if (record.d_place == DNSResourceRecord::ANSWER ||
1005 record.d_place == DNSResourceRecord::ADDITIONAL) {
1006 // Create a string that represent a triplet of (qname, qtype and RR[type, name, content])
1007 std::stringstream ss;
1008 ss << dname.toDNSStringLC() << ":" << qtype << ":" << qtype << ":" << record.d_type << ":" << record.d_name.toDNSStringLC() << ":" << record.d_content->getZoneRepresentation();
1009 if (t_udrDBp && t_udrDBp->isUniqueResponse(ss.str())) {
ff4d391d
NC
1010 if (g_udrLog) {
1011 // This should also probably log to a dedicated file.
1012 g_log<<Logger::Notice<<"Unique response observed: qname="<<dname.toLogString()<<" qtype="<<QType(qtype).getName()<< " rrtype=" << QType(record.d_type).getName() << " rrname=" << record.d_name.toLogString() << " rrcontent=" << record.d_content->getZoneRepresentation() << endl;
41c542ec
NC
1013 }
1014 ret = true;
1015 }
1016 }
1017 return ret;
1018}
af1377b7
NC
1019#endif /* NOD_ENABLED */
1020
d187038c 1021static void startDoResolve(void *p)
288f4aa9 1022{
9a864da4 1023 auto dc=std::unique_ptr<DNSComboWriter>(reinterpret_cast<DNSComboWriter*>(p));
288f4aa9 1024 try {
5af86fdc
RG
1025 if (t_queryring)
1026 t_queryring->push_back(make_pair(dc->d_mdp.d_qname, dc->d_mdp.d_qtype));
92011b8f 1027
32015748 1028 uint16_t maxanswersize = dc->d_tcp ? 65535 : min(static_cast<uint16_t>(512), g_udpTruncationThreshold);
7f7b8d55 1029 EDNSOpts edo;
5164bac3 1030 std::vector<pair<uint16_t, string> > ednsOpts;
eb9444be 1031 bool variableAnswer = dc->d_variable;
8e079f3a 1032 bool haveEDNS=false;
ca2526f5
NC
1033#ifdef NOD_ENABLED
1034 bool hasUDR = false;
1035#endif /* NOD_ENABLED */
f1db0de2
PL
1036 DNSPacketWriter::optvect_t returnedEdnsOptions; // Here we stuff all the options for the return packet
1037 uint8_t ednsExtRCode = 0;
8e079f3a 1038 if(getEDNSOpts(dc->d_mdp, &edo)) {
f1db0de2
PL
1039 haveEDNS=true;
1040 if (edo.d_version != 0) {
1041 ednsExtRCode = ERCode::BADVERS;
1042 }
1043
32015748
RG
1044 if(!dc->d_tcp) {
1045 /* rfc6891 6.2.3:
1046 "Values lower than 512 MUST be treated as equal to 512."
1047 */
1048 maxanswersize = min(static_cast<uint16_t>(edo.d_packetsize >= 512 ? edo.d_packetsize : 512), g_udpTruncationThreshold);
1049 }
5164bac3 1050 ednsOpts = edo.d_options;
3af35968 1051 maxanswersize -= 11; // EDNS header size
b40562da 1052
1f691b94
PL
1053 for (const auto& o : edo.d_options) {
1054 if (o.first == EDNSOptionCode::ECS && g_useIncomingECS && !dc->d_ecsParsed) {
1055 dc->d_ecsFound = getEDNSSubnetOptsFromString(o.second, &dc->d_ednssubnet);
1056 } else if (o.first == EDNSOptionCode::NSID) {
f1db0de2 1057 const static string mode_server_id = ::arg()["server-id"];
8a42919a
PL
1058 if(mode_server_id != "disabled" && !mode_server_id.empty() &&
1059 maxanswersize > (2 + 2 + mode_server_id.size())) {
f1db0de2
PL
1060 returnedEdnsOptions.push_back(make_pair(EDNSOptionCode::NSID, mode_server_id));
1061 variableAnswer = true; // Can't packetcache an answer with NSID
1062 // Option Code and Option Length are both 2
1063 maxanswersize -= 2 + 2 + mode_server_id.size();
1064 }
b40562da
RG
1065 }
1066 }
10321a98 1067 }
b40562da
RG
1068 /* perhaps there was no EDNS or no ECS but by now we looked */
1069 dc->d_ecsParsed = true;
e325f20c 1070 vector<DNSRecord> ret;
ea634573 1071 vector<uint8_t> packet;
b23b8614 1072
ad42489c 1073 auto luaconfsLocal = g_luaconfs.getLocal();
b8470add
PL
1074 // Used to tell syncres later on if we should apply NSDNAME and NSIP RPZ triggers for this query
1075 bool wantsRPZ(true);
1fbc6dc5 1076 boost::optional<RecProtoBufMessage> pbMessage(boost::none);
f1c7929a 1077 bool logResponse = false;
aa7929a3 1078#ifdef HAVE_PROTOBUF
63341e8d 1079 if (checkProtobufExport(luaconfsLocal)) {
b773359c 1080 logResponse = t_protobufServers && luaconfsLocal->protobufExportConfig.logResponses;
5cc8371b 1081 Netmask requestorNM(dc->d_source, dc->d_source.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
e1c8a4bb 1082 const ComboAddress& requestor = requestorNM.getMaskedNetwork();
0bd2e252 1083 pbMessage = RecProtoBufMessage(RecProtoBufMessage::Response, dc->d_uuid, &requestor, &dc->d_destination, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass, dc->d_mdp.d_header.id, dc->d_tcp, 0);
c165308b 1084 pbMessage->setServerIdentity(SyncRes::s_serverID);
d362f7c1 1085 pbMessage->setEDNSSubnet(dc->d_ednssubnet.source, dc->d_ednssubnet.source.isIpv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
d9d3f9c1
RG
1086 }
1087#endif /* HAVE_PROTOBUF */
ad42489c 1088
3ddb9247 1089 DNSPacketWriter pw(packet, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
ea634573
BH
1090
1091 pw.getHeader()->aa=0;
1092 pw.getHeader()->ra=1;
c154c8a4 1093 pw.getHeader()->qr=1;
bb4bdbaf 1094 pw.getHeader()->tc=0;
ea634573 1095 pw.getHeader()->id=dc->d_mdp.d_header.id;
10321a98 1096 pw.getHeader()->rd=dc->d_mdp.d_header.rd;
57769f13 1097 pw.getHeader()->cd=dc->d_mdp.d_header.cd;
ea634573 1098
70fb28d9
RG
1099 /* This is the lowest TTL seen in the records of the response,
1100 so we can't cache it for longer than this value.
1101 If we have a TTL cap, this value can't be larger than the
1102 cap no matter what. */
1103 uint32_t minTTL = dc->d_ttlCap;
904d3219
PD
1104
1105 SyncRes sr(dc->d_now);
0c43f455 1106
2e921ec6 1107 bool DNSSECOK=false;
3457a2a0 1108 if(t_pdl) {
f26bf547 1109 sr.setLuaEngine(t_pdl);
3457a2a0 1110 }
9eec8c98 1111 if(g_dnssecmode != DNSSECMode::Off) {
30ee601a 1112 sr.setDoDNSSEC(true);
9eec8c98
PL
1113
1114 // Does the requestor want DNSSEC records?
d6c335ab 1115 if(edo.d_extFlags & EDNSOpts::DNSSECOK) {
9eec8c98
PL
1116 DNSSECOK=true;
1117 g_stats.dnssecQueries++;
1118 }
88c33dca
RG
1119 if (dc->d_mdp.d_header.cd) {
1120 /* Per rfc6840 section 5.9, "When processing a request with
1121 the Checking Disabled (CD) bit set, a resolver SHOULD attempt
1122 to return all response data, even data that has failed DNSSEC
1123 validation. */
1124 ++g_stats.dnssecCheckDisabledQueries;
1125 }
1126 if (dc->d_mdp.d_header.ad) {
1127 /* Per rfc6840 section 5.7, "the AD bit in a query as a signal
1128 indicating that the requester understands and is interested in the
1129 value of the AD bit in the response. This allows a requester to
1130 indicate that it understands the AD bit without also requesting
1131 DNSSEC data via the DO bit. */
1132 ++g_stats.dnssecAuthenticDataQueries;
1133 }
9eec8c98
PL
1134 } else {
1135 // Ignore the client-set CD flag
1136 pw.getHeader()->cd=0;
5b9853c9 1137 }
0c43f455
RG
1138 sr.setDNSSECValidationRequested(g_dnssecmode == DNSSECMode::ValidateAll || g_dnssecmode==DNSSECMode::ValidateForLog || ((dc->d_mdp.d_header.ad || DNSSECOK) && g_dnssecmode==DNSSECMode::Process));
1139
4898a348 1140#ifdef HAVE_PROTOBUF
30ee601a 1141 sr.setInitialRequestId(dc->d_uuid);
b773359c 1142 sr.setOutgoingProtobufServers(t_outgoingProtobufServers);
4898a348 1143#endif
0c43f455 1144
2fe3354d 1145 sr.setQuerySource(dc->d_remote, g_useIncomingECS && !dc->d_ednssubnet.source.empty() ? boost::optional<const EDNSSubnetOpts&>(dc->d_ednssubnet) : boost::none);
57769f13 1146
904d3219 1147 bool tracedQuery=false; // we could consider letting Lua know about this too
9fc36e90 1148 bool shouldNotValidate = false;
904d3219 1149
ef3b6cd7
RG
1150 /* preresolve expects res (dq.rcode) to be set to RCode::NoError by default */
1151 int res = RCode::NoError;
1f1ca368 1152 DNSFilterEngine::Policy appliedPolicy;
6da513b2 1153 std::vector<DNSRecord> spoofed;
f1c7929a 1154 RecursorLua4::DNSQuestion dq(dc->d_source, dc->d_destination, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_tcp, variableAnswer, wantsRPZ, logResponse);
d6c335ab 1155 dq.ednsFlags = &edo.d_extFlags;
5164bac3 1156 dq.ednsOptions = &ednsOpts;
6e505c5e
RG
1157 dq.tag = dc->d_tag;
1158 dq.discardedPolicies = &sr.d_discardedPolicies;
1159 dq.policyTags = &dc->d_policyTags;
1160 dq.appliedPolicy = &appliedPolicy;
1161 dq.currentRecords = &ret;
1162 dq.dh = &dc->d_mdp.d_header;
05c74122 1163 dq.data = dc->d_data;
67e31ebe
RG
1164#ifdef HAVE_PROTOBUF
1165 dq.requestorId = dc->d_requestorId;
590388d2 1166 dq.deviceId = dc->d_deviceId;
67e31ebe 1167#endif
ba21fcfe 1168
6cf96227
PL
1169 if(ednsExtRCode != 0) {
1170 goto sendit;
1171 }
1172
e661a20b 1173 if(dc->d_mdp.d_qtype==QType::ANY && !dc->d_tcp && g_anyToTcp) {
56b4d21b
PD
1174 pw.getHeader()->tc = 1;
1175 res = 0;
1176 variableAnswer = true;
e661a20b
PD
1177 goto sendit;
1178 }
1179
f26bf547 1180 if(t_traceRegex && t_traceRegex->match(dc->d_mdp.d_qname.toString())) {
77499b05
BH
1181 sr.setLogMode(SyncRes::Store);
1182 tracedQuery=true;
1183 }
3ddb9247 1184
8f7473d7 1185
976ec823 1186 if(!g_quiet || tracedQuery) {
e6a9dde5 1187 g_log<<Logger::Warning<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] " << (dc->d_tcp ? "TCP " : "") << "question for '"<<dc->d_mdp.d_qname<<"|"
976ec823 1188 <<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<"' from "<<dc->getRemote();
b40562da 1189 if(!dc->d_ednssubnet.source.empty()) {
e6a9dde5 1190 g_log<<" (ecs "<<dc->d_ednssubnet.source.toString()<<")";
6e986f5e 1191 }
e6a9dde5 1192 g_log<<endl;
976ec823 1193 }
c75a6a9e 1194
fededf47 1195 sr.setId(MT->getTid());
67828389 1196 if(!dc->d_mdp.d_header.rd)
c836dc19
BH
1197 sr.setCacheOnly();
1198
f26bf547
RG
1199 if (t_pdl) {
1200 t_pdl->prerpz(dq, res);
0a273054
RG
1201 }
1202
db486de5 1203 // Check if the query has a policy attached to it
0a273054 1204 if (wantsRPZ) {
5cc8371b 1205 appliedPolicy = luaconfsLocal->dfe.getQueryPolicy(dc->d_mdp.d_qname, dc->d_source, sr.d_discardedPolicies);
0a273054 1206 }
644dd1da 1207
54be222b 1208 // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
f26bf547 1209 if(!t_pdl || !t_pdl->preresolve(dq, res)) {
b8470add 1210
30ee601a 1211 sr.setWantsRPZ(wantsRPZ);
b8470add
PL
1212 if(wantsRPZ) {
1213 switch(appliedPolicy.d_kind) {
1214 case DNSFilterEngine::PolicyKind::NoAction:
1215 break;
1216 case DNSFilterEngine::PolicyKind::Drop:
1217 g_stats.policyDrops++;
7a25883a 1218 g_stats.policyResults[appliedPolicy.d_kind]++;
b8470add
PL
1219 return;
1220 case DNSFilterEngine::PolicyKind::NXDOMAIN:
1221 g_stats.policyResults[appliedPolicy.d_kind]++;
1222 res=RCode::NXDomain;
1223 goto haveAnswer;
1224 case DNSFilterEngine::PolicyKind::NODATA:
1225 g_stats.policyResults[appliedPolicy.d_kind]++;
1226 res=RCode::NoError;
db486de5 1227 goto haveAnswer;
b8470add
PL
1228 case DNSFilterEngine::PolicyKind::Custom:
1229 g_stats.policyResults[appliedPolicy.d_kind]++;
1230 res=RCode::NoError;
6da513b2
RG
1231 spoofed=appliedPolicy.getCustomRecords(dc->d_mdp.d_qname, dc->d_mdp.d_qtype);
1232 for (const auto& dr : spoofed) {
1233 ret.push_back(dr);
1234 handleRPZCustom(dr, QType(dc->d_mdp.d_qtype), sr, res, ret);
1235 }
b8470add
PL
1236 goto haveAnswer;
1237 case DNSFilterEngine::PolicyKind::Truncate:
1238 if(!dc->d_tcp) {
1239 g_stats.policyResults[appliedPolicy.d_kind]++;
1240 res=RCode::NoError;
1241 pw.getHeader()->tc=1;
1242 goto haveAnswer;
1243 }
1244 break;
1245 }
db486de5
PL
1246 }
1247
b8470add 1248 // Query got not handled for QNAME Policy reasons, now actually go out to find an answer
44971ca0
PD
1249 try {
1250 res = sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret);
9fc36e90 1251 shouldNotValidate = sr.wasOutOfBand();
44971ca0
PD
1252 }
1253 catch(ImmediateServFailException &e) {
854d44e3 1254 if(g_logCommonErrors)
e6a9dde5 1255 g_log<<Logger::Notice<<"Sending SERVFAIL to "<<dc->getRemote()<<" during resolve of '"<<dc->d_mdp.d_qname<<"' because: "<<e.reason<<endl;
44971ca0
PD
1256 res = RCode::ServFail;
1257 }
4485aa35 1258
1921a4c2
RG
1259 dq.validationState = sr.getValidationState();
1260
b8470add
PL
1261 // During lookup, an NSDNAME or NSIP trigger was hit in RPZ
1262 if (res == -2) { // XXX This block should be macro'd, it is repeated post-resolve.
1263 appliedPolicy = sr.d_appliedPolicy;
1264 g_stats.policyResults[appliedPolicy.d_kind]++;
1265 switch(appliedPolicy.d_kind) {
1266 case DNSFilterEngine::PolicyKind::NoAction: // This can never happen
1267 throw PDNSException("NoAction policy returned while a NSDNAME or NSIP trigger was hit");
1268 case DNSFilterEngine::PolicyKind::Drop:
1269 g_stats.policyDrops++;
b8470add
PL
1270 return;
1271 case DNSFilterEngine::PolicyKind::NXDOMAIN:
1272 ret.clear();
1273 res=RCode::NXDomain;
1274 goto haveAnswer;
1275
1276 case DNSFilterEngine::PolicyKind::NODATA:
1277 ret.clear();
1278 res=RCode::NoError;
1279 goto haveAnswer;
1280
1281 case DNSFilterEngine::PolicyKind::Truncate:
1282 if(!dc->d_tcp) {
1283 ret.clear();
1284 res=RCode::NoError;
1285 pw.getHeader()->tc=1;
1286 goto haveAnswer;
1287 }
1288 break;
1289
1290 case DNSFilterEngine::PolicyKind::Custom:
1291 ret.clear();
1292 res=RCode::NoError;
6da513b2
RG
1293 spoofed=appliedPolicy.getCustomRecords(dc->d_mdp.d_qname, dc->d_mdp.d_qtype);
1294 for (const auto& dr : spoofed) {
1295 ret.push_back(dr);
1296 handleRPZCustom(dr, QType(dc->d_mdp.d_qtype), sr, res, ret);
1297 }
b8470add
PL
1298 goto haveAnswer;
1299 }
1300 }
1301
1302 if (wantsRPZ) {
1f1ca368 1303 appliedPolicy = luaconfsLocal->dfe.getPostPolicy(ret, sr.d_discardedPolicies);
b8470add 1304 }
db486de5 1305
f26bf547 1306 if(t_pdl) {
db486de5
PL
1307 if(res == RCode::NoError) {
1308 auto i=ret.cbegin();
1309 for(; i!= ret.cend(); ++i)
1310 if(i->d_type == dc->d_mdp.d_qtype && i->d_place == DNSResourceRecord::ANSWER)
1311 break;
f26bf547 1312 if(i == ret.cend() && t_pdl->nodata(dq, res))
3ca4e735
PL
1313 shouldNotValidate = true;
1314
db486de5 1315 }
f26bf547 1316 else if(res == RCode::NXDomain && t_pdl->nxdomain(dq, res))
3ca4e735 1317 shouldNotValidate = true;
db486de5 1318
f26bf547 1319 if(t_pdl->postresolve(dq, res))
3ca4e735 1320 shouldNotValidate = true;
db486de5
PL
1321 }
1322
b8470add
PL
1323 if (wantsRPZ) { //XXX This block is repeated, see above
1324 g_stats.policyResults[appliedPolicy.d_kind]++;
1325 switch(appliedPolicy.d_kind) {
1326 case DNSFilterEngine::PolicyKind::NoAction:
1327 break;
1328 case DNSFilterEngine::PolicyKind::Drop:
1329 g_stats.policyDrops++;
b8470add
PL
1330 return;
1331 case DNSFilterEngine::PolicyKind::NXDOMAIN:
1332 ret.clear();
1333 res=RCode::NXDomain;
1334 goto haveAnswer;
1335
1336 case DNSFilterEngine::PolicyKind::NODATA:
1337 ret.clear();
1338 res=RCode::NoError;
1339 goto haveAnswer;
1340
1341 case DNSFilterEngine::PolicyKind::Truncate:
1342 if(!dc->d_tcp) {
1343 ret.clear();
1344 res=RCode::NoError;
1345 pw.getHeader()->tc=1;
1346 goto haveAnswer;
1347 }
1348 break;
1349
1350 case DNSFilterEngine::PolicyKind::Custom:
1351 ret.clear();
1352 res=RCode::NoError;
6da513b2
RG
1353 spoofed=appliedPolicy.getCustomRecords(dc->d_mdp.d_qname, dc->d_mdp.d_qtype);
1354 for (const auto& dr : spoofed) {
1355 ret.push_back(dr);
1356 handleRPZCustom(dr, QType(dc->d_mdp.d_qtype), sr, res, ret);
1357 }
b8470add
PL
1358 goto haveAnswer;
1359 }
644dd1da 1360 }
4485aa35 1361 }
644dd1da 1362 haveAnswer:;
3e8216c8 1363 if(res == PolicyDecision::DROP) {
e9c2ad3a 1364 g_stats.policyDrops++;
ae7e77ad 1365 return;
3ddb9247 1366 }
9cdfab64 1367 if(tracedQuery || res == -1 || res == RCode::ServFail || pw.getHeader()->rcode == RCode::ServFail)
1dc8f4d0 1368 {
85ffbc53
PD
1369 string trace(sr.getTrace());
1370 if(!trace.empty()) {
1371 vector<string> lines;
1372 boost::split(lines, trace, boost::is_any_of("\n"));
1dc8f4d0 1373 for(const string& line : lines) {
85ffbc53 1374 if(!line.empty())
e6a9dde5 1375 g_log<<Logger::Warning<< line << endl;
85ffbc53
PD
1376 }
1377 }
1378 }
3ddb9247 1379
9cdfab64 1380 if(res == -1) {
0fe1d080
PD
1381 pw.getHeader()->rcode=RCode::ServFail;
1382 // no commit here, because no record
1383 g_stats.servFails++;
1384 }
288f4aa9 1385 else {
ea634573 1386 pw.getHeader()->rcode=res;
92011b8f 1387
f3fe4ae6 1388 // Does the validation mode or query demand validation?
0c43f455 1389 if(!shouldNotValidate && sr.isDNSSECValidationRequested()) {
b25cae9a 1390 try {
f3fe4ae6 1391 if(sr.doLog()) {
e6a9dde5 1392 g_log<<Logger::Warning<<"Starting validation of answer to "<<dc->d_mdp.d_qname<<"|"<<QType(dc->d_mdp.d_qtype).getName()<<" for "<<dc->getRemote()<<endl;
2e921ec6 1393 }
4d2be65d
RG
1394
1395 auto state = sr.getValidationState();
1396
b25cae9a 1397 if(state == Secure) {
2e921ec6 1398 if(sr.doLog()) {
e6a9dde5 1399 g_log<<Logger::Warning<<"Answer to "<<dc->d_mdp.d_qname<<"|"<<QType(dc->d_mdp.d_qtype).getName()<<" for "<<dc->getRemote()<<" validates correctly"<<endl;
2e921ec6 1400 }
b25cae9a 1401
1402 // Is the query source interested in the value of the ad-bit?
885c8881 1403 if (dc->d_mdp.d_header.ad || DNSSECOK)
b25cae9a 1404 pw.getHeader()->ad=1;
1405 }
1406 else if(state == Insecure) {
f3fe4ae6 1407 if(sr.doLog()) {
e6a9dde5 1408 g_log<<Logger::Warning<<"Answer to "<<dc->d_mdp.d_qname<<"|"<<QType(dc->d_mdp.d_qtype).getName()<<" for "<<dc->getRemote()<<" validates as Insecure"<<endl;
12ce523e 1409 }
b25cae9a 1410
1411 pw.getHeader()->ad=0;
f3fe4ae6 1412 }
b25cae9a 1413 else if(state == Bogus) {
66f2e6ad
KM
1414 if(t_bogusremotes)
1415 t_bogusremotes->push_back(dc->d_source);
1416 if(t_bogusqueryring)
1417 t_bogusqueryring->push_back(make_pair(dc->d_mdp.d_qname, dc->d_mdp.d_qtype));
c87e1876 1418 if(g_dnssecLogBogus || sr.doLog() || g_dnssecmode == DNSSECMode::ValidateForLog) {
e6a9dde5 1419 g_log<<Logger::Warning<<"Answer to "<<dc->d_mdp.d_qname<<"|"<<QType(dc->d_mdp.d_qtype).getName()<<" for "<<dc->getRemote()<<" validates as Bogus"<<endl;
b25cae9a 1420 }
1421
1422 // Does the query or validation mode sending out a SERVFAIL on validation errors?
885c8881 1423 if(!pw.getHeader()->cd && (g_dnssecmode == DNSSECMode::ValidateAll || dc->d_mdp.d_header.ad || DNSSECOK)) {
b25cae9a 1424 if(sr.doLog()) {
e6a9dde5 1425 g_log<<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 1426 }
1427
1428 pw.getHeader()->rcode=RCode::ServFail;
1429 goto sendit;
1430 } else {
1431 if(sr.doLog()) {
e6a9dde5 1432 g_log<<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 1433 }
1434 }
1435 }
1436 }
1437 catch(ImmediateServFailException &e) {
1438 if(g_logCommonErrors)
e6a9dde5 1439 g_log<<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 1440 pw.getHeader()->rcode=RCode::ServFail;
1441 goto sendit;
f3fe4ae6 1442 }
b3f0ed10 1443 }
1444
c154c8a4 1445 if(ret.size()) {
92476c8b 1446 orderAndShuffle(ret);
5cc8371b 1447 if(auto sl = luaconfsLocal->sortlist.getOrderCmp(dc->d_source)) {
20d84f77 1448 stable_sort(ret.begin(), ret.end(), *sl);
3e61e7f7 1449 variableAnswer=true;
1450 }
8e079f3a 1451 }
0afa32d4
RG
1452
1453 bool needCommit = false;
8e079f3a 1454 for(auto i=ret.cbegin(); i!=ret.cend(); ++i) {
3e80ebce
KM
1455 if( ! DNSSECOK &&
1456 ( i->d_type == QType::NSEC3 ||
1457 (
1458 ( i->d_type == QType::RRSIG || i->d_type==QType::NSEC ) &&
1459 (
1460 ( dc->d_mdp.d_qtype != i->d_type && dc->d_mdp.d_qtype != QType::ANY ) ||
1461 i->d_place != DNSResourceRecord::ANSWER
1462 )
1463 )
1464 )
1465 ) {
2e921ec6 1466 continue;
3e80ebce
KM
1467 }
1468
70fb28d9 1469 if (!addRecordToPacket(pw, *i, minTTL, dc->d_ttlCap, maxanswersize)) {
97c6d7e5
RG
1470 needCommit = false;
1471 break;
1472 }
1473 needCommit = true;
1474
41c542ec
NC
1475#ifdef NOD_ENABLED
1476 bool udr = false;
1477 if (g_udrEnabled) {
1478 udr = udrCheckUniqueDNSRecord(dc->d_mdp.d_qname, dc->d_mdp.d_qtype, *i);
ca2526f5
NC
1479 if (!hasUDR && udr)
1480 hasUDR = true;
41c542ec
NC
1481 }
1482#endif /* NOD ENABLED */
1483
aa7929a3 1484#ifdef HAVE_PROTOBUF
b773359c 1485 if (t_protobufServers) {
41c542ec
NC
1486#ifdef NOD_ENABLED
1487 pbMessage->addRR(*i, luaconfsLocal->protobufExportConfig.exportTypes, udr);
1488#else
0bd2e252 1489 pbMessage->addRR(*i, luaconfsLocal->protobufExportConfig.exportTypes);
41c542ec 1490#endif /* NOD_ENABLED */
aa7929a3
RG
1491 }
1492#endif
ea634573 1493 }
0afa32d4 1494 if(needCommit)
8e079f3a 1495 pw.commit();
288f4aa9 1496 }
10321a98 1497 sendit:;
b3f0ed10 1498
a0ddd130 1499 if(g_useIncomingECS && dc->d_ecsFound && !sr.wasVariable() && !variableAnswer) {
9837850d 1500 // cerr<<"Stuffing in a 0 scope because answer is static"<<endl;
5a7f99b4 1501 EDNSSubnetOpts eo;
1502 eo.source = dc->d_ednssubnet.source;
1503 ComboAddress sa;
1ef18cab 1504 sa.reset();
5a7f99b4 1505 sa.sin4.sin_family = eo.source.getNetwork().sin4.sin_family;
1506 eo.scope = Netmask(sa, 0);
1507
1508 returnedEdnsOptions.push_back(make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(eo)));
1509 }
1510
97c6d7e5
RG
1511 if (haveEDNS) {
1512 /* we try to add the EDNS OPT RR even for truncated answers,
1513 as rfc6891 states:
1514 "The minimal response MUST be the DNS header, question section, and an
1515 OPT record. This MUST also occur when a truncated response (using
1516 the DNS header's TC bit) is returned."
1517 */
9b60fb71 1518 pw.addOpt(512, ednsExtRCode, DNSSECOK ? EDNSOpts::DNSSECOK : 0, returnedEdnsOptions);
1f691b94 1519 pw.commit();
97c6d7e5
RG
1520 }
1521
79332bff 1522 g_rs.submitResponse(dc->d_mdp.d_qtype, packet.size(), !dc->d_tcp);
5cc8371b 1523 updateResponseStats(res, dc->d_source, packet.size(), &dc->d_mdp.d_qname, dc->d_mdp.d_qtype);
ff4d391d
NC
1524#ifdef NOD_ENABLED
1525 bool nod = false;
1526 if (g_nodEnabled) {
1527 if (nodCheckNewDomain(dc->d_mdp.d_qname))
1528 nod = true;
1529 }
1530#endif /* NOD_ENABLED */
aa7929a3 1531#ifdef HAVE_PROTOBUF
b773359c 1532 if (t_protobufServers && logResponse && !(luaconfsLocal->protobufExportConfig.taggedOnly && (!appliedPolicy.d_name || appliedPolicy.d_name->empty()) && dc->d_policyTags.empty())) {
d362f7c1
RG
1533 pbMessage->setBytes(packet.size());
1534 pbMessage->setResponseCode(pw.getHeader()->rcode);
0a273054 1535 if (appliedPolicy.d_name) {
d362f7c1
RG
1536 pbMessage->setAppliedPolicy(*appliedPolicy.d_name);
1537 pbMessage->setAppliedPolicyType(appliedPolicy.d_type);
0a273054 1538 }
d362f7c1
RG
1539 pbMessage->setPolicyTags(dc->d_policyTags);
1540 pbMessage->setQueryTime(dc->d_now.tv_sec, dc->d_now.tv_usec);
1541 pbMessage->setRequestorId(dq.requestorId);
1542 pbMessage->setDeviceId(dq.deviceId);
41c542ec
NC
1543#ifdef NOD_ENABLED
1544 if (g_nodEnabled) {
ca2526f5 1545 if (nod) {
41c542ec 1546 pbMessage->setNOD(true);
ca2526f5
NC
1547 pbMessage->addPolicyTag(g_nod_pbtag);
1548 }
1549 if (hasUDR) {
1550 pbMessage->addPolicyTag(g_udr_pbtag);
1551 }
41c542ec
NC
1552 }
1553#endif /* NOD_ENABLED */
b773359c 1554 protobufLogResponse(*pbMessage);
ac238ea7 1555#ifdef NOD_ENABLED
ca2526f5
NC
1556 if (g_nodEnabled) {
1557 pbMessage->setNOD(false);
1558 pbMessage->clearUDR();
1559 if (nod)
1560 pbMessage->removePolicyTag(g_nod_pbtag);
1561 if (hasUDR)
1562 pbMessage->removePolicyTag(g_udr_pbtag);
1563 }
ac238ea7 1564#endif /* NOD_ENABLED */
aa7929a3
RG
1565 }
1566#endif
ea634573 1567 if(!dc->d_tcp) {
b71b60ee 1568 struct msghdr msgh;
1569 struct iovec iov;
1570 char cbuf[256];
1571 fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)&*packet.begin(), packet.size(), &dc->d_remote);
2c0af54f
PD
1572 msgh.msg_control=NULL;
1573
cbc03320 1574 if(g_fromtosockets.count(dc->d_socket)) {
fbe2a2e0 1575 addCMsgSrcAddr(&msgh, cbuf, &dc->d_local, 0);
2c0af54f 1576 }
cbc03320 1577 if(sendmsg(dc->d_socket, &msgh, 0) < 0 && g_logCommonErrors)
e6a9dde5 1578 g_log<<Logger::Warning<<"Sending UDP reply to client "<<dc->getRemote()<<" failed with: "<<strerror(errno)<<endl;
70fb28d9 1579
49dc532e 1580 if(variableAnswer || sr.wasVariable()) {
1ef18cab 1581 g_stats.variableResponses++;
49dc532e 1582 }
3762e821 1583 if(!SyncRes::s_nopacketcache && !variableAnswer && !sr.wasVariable() ) {
b5e675a7 1584 t_packetCache->insertResponsePacket(dc->d_tag, dc->d_qhash, std::move(dc->d_query), dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass,
76e2b9e3 1585 string((const char*)&*packet.begin(), packet.size()),
3ddb9247 1586 g_now.tv_sec,
76e2b9e3 1587 pw.getHeader()->rcode == RCode::ServFail ? SyncRes::s_packetcacheservfailttl :
d9d3f9c1 1588 min(minTTL,SyncRes::s_packetcachettl),
88694a6a 1589 dq.validationState,
08b02366
RG
1590 dc->d_ecsBegin,
1591 dc->d_ecsEnd,
4b0bdd5f 1592 std::move(pbMessage));
1051f8a9 1593 }
3762e821 1594 // else cerr<<"Not putting in packet cache: "<<sr.wasVariable()<<endl;
feccc9fc 1595 }
9c495589
BH
1596 else {
1597 char buf[2];
ea634573
BH
1598 buf[0]=packet.size()/256;
1599 buf[1]=packet.size()%256;
feccc9fc 1600
c038218b 1601 Utility::iovec iov[2];
feccc9fc 1602
ea634573
BH
1603 iov[0].iov_base=(void*)buf; iov[0].iov_len=2;
1604 iov[1].iov_base=(void*)&*packet.begin(); iov[1].iov_len = packet.size();
feccc9fc 1605
dd079764 1606 int wret=Utility::writev(dc->d_socket, iov, 2);
0e9d9ce2 1607 bool hadError=true;
feccc9fc 1608
dd079764 1609 if(wret == 0)
e6a9dde5 1610 g_log<<Logger::Error<<"EOF writing TCP answer to "<<dc->getRemote()<<endl;
dd079764 1611 else if(wret < 0 )
e6a9dde5 1612 g_log<<Logger::Error<<"Error writing TCP answer to "<<dc->getRemote()<<": "<< strerror(errno) <<endl;
dd079764 1613 else if((unsigned int)wret != 2 + packet.size())
e6a9dde5 1614 g_log<<Logger::Error<<"Oops, partial answer sent to "<<dc->getRemote()<<" for "<<dc->d_mdp.d_qname<<" (size="<< (2 + packet.size()) <<", sent "<<wret<<")"<<endl;
0e9d9ce2 1615 else
18af64a8 1616 hadError=false;
3ddb9247 1617
09e6702a 1618 // update tcp connection status, either by closing or moving to 'BYTE0'
3ddb9247 1619
09e6702a 1620 if(hadError) {
18af64a8 1621 // no need to remove us from FDM, we weren't there
c36bc97a 1622 dc->d_socket = -1;
09e6702a 1623 }
a6ae6414 1624 else {
fde296a3
RG
1625 dc->d_tcpConnection->queriesCount++;
1626 if (g_tcpMaxQueriesPerConn && dc->d_tcpConnection->queriesCount >= g_tcpMaxQueriesPerConn) {
1627 dc->d_socket = -1;
1628 }
1629 else {
1630 dc->d_tcpConnection->state=TCPConnection::BYTE0;
1631 Utility::gettimeofday(&g_now, 0); // needs to be updated
27ae2e3c
RG
1632 struct timeval ttd = g_now;
1633 ttd.tv_sec += g_tcpTimeout;
1634
1635 t_fdm->addReadFD(dc->d_socket, handleRunningTCPQuestion, dc->d_tcpConnection, &ttd);
fde296a3 1636 }
0e9d9ce2 1637 }
9c495589 1638 }
2c9119cd 1639 float spent=makeFloat(sr.getNow()-dc->d_now);
1d5b3ce6 1640 if(!g_quiet) {
e6a9dde5
PL
1641 g_log<<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);
1642 g_log<<"': "<<ntohs(pw.getHeader()->ancount)<<" answers, "<<ntohs(pw.getHeader()->arcount)<<" additional, took "<<sr.d_outqueries<<" packets, "<<
2c9119cd 1643 sr.d_totUsec/1000.0<<" netw ms, "<< spent*1000.0<<" tot ms, "<<
1644 sr.d_throttledqueries<<" throttled, "<<sr.d_timeouts<<" timeouts, "<<sr.d_tcpoutqueries<<" tcp connections, rcode="<< res;
1645
1646 if(!shouldNotValidate && sr.isDNSSECValidationRequested()) {
e6a9dde5 1647 g_log<< ", dnssec="<<vStates[sr.getValidationState()];
2c9119cd 1648 }
1649
e6a9dde5 1650 g_log<<endl;
2c9119cd 1651
c75a6a9e 1652 }
b23b8614 1653
f7b8cffa
RG
1654 if (sr.d_outqueries || sr.d_authzonequeries) {
1655 t_RC->cacheMisses++;
1656 }
1657 else {
1658 t_RC->cacheHits++;
1659 }
2c9119cd 1660
fe213470
BH
1661 if(spent < 0.001)
1662 g_stats.answers0_1++;
1663 else if(spent < 0.010)
1664 g_stats.answers1_10++;
1665 else if(spent < 0.1)
1666 g_stats.answers10_100++;
1667 else if(spent < 1.0)
1668 g_stats.answers100_1000++;
1669 else
1670 g_stats.answersSlow++;
1671
574af7ea 1672 uint64_t newLat=(uint64_t)(spent*1000000);
b841314c 1673 newLat = min(newLat,(uint64_t)(((uint64_t) g_networkTimeoutMsec)*1000)); // outliers of several minutes exist..
08f3f638 1674 g_stats.avgLatencyUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyUsec + (float)newLat/g_latencyStatSize;
0a6b1027 1675 // no worries, we do this for packet cache hits elsewhere
19178da9 1676
1677 auto ourtime = 1000.0*spent-sr.d_totUsec/1000.0; // in msec
1678 if(ourtime < 1)
1679 g_stats.ourtime0_1++;
1680 else if(ourtime < 2)
1681 g_stats.ourtime1_2++;
1682 else if(ourtime < 4)
1683 g_stats.ourtime2_4++;
1684 else if(ourtime < 8)
1685 g_stats.ourtime4_8++;
1686 else if(ourtime < 16)
1687 g_stats.ourtime8_16++;
1688 else if(ourtime < 32)
1689 g_stats.ourtime16_32++;
1690 else {
1691 // cerr<<"SLOW: "<<ourtime<<"ms -> "<<dc->d_mdp.d_qname<<"|"<<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<endl;
1692 g_stats.ourtimeSlow++;
1693 }
042da1a1 1694 if(ourtime >= 0.0) {
1695 newLat=ourtime*1000; // usec
1696 g_stats.avgLatencyOursUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyOursUsec + (float)newLat/g_latencyStatSize;
1697 }
c6d04bdc 1698 // cout<<dc->d_mdp.d_qname<<"\t"<<MT->getUsec()<<"\t"<<sr.d_outqueries<<endl;
288f4aa9 1699 }
3f81d239 1700 catch(PDNSException &ae) {
e6a9dde5 1701 g_log<<Logger::Error<<"startDoResolve problem "<<makeLoginfo(dc)<<": "<<ae.reason<<endl;
288f4aa9 1702 }
16ce7f18
JS
1703 catch(const MOADNSException &mde) {
1704 g_log<<Logger::Error<<"DNS parser error "<<makeLoginfo(dc) <<": "<<dc->d_mdp.d_qname<<", "<<mde.what()<<endl;
7b1469bb 1705 }
fdbf35ac 1706 catch(std::exception& e) {
e6a9dde5 1707 g_log<<Logger::Error<<"STL error "<< makeLoginfo(dc)<<": "<<e.what();
068c7634
PD
1708
1709 // Luawrapper nests the exception from Lua, so we unnest it here
1710 try {
1711 std::rethrow_if_nested(e);
2010ac95 1712 } catch(const std::exception& ne) {
e6a9dde5 1713 g_log<<". Extra info: "<<ne.what();
068c7634
PD
1714 } catch(...) {}
1715
e6a9dde5 1716 g_log<<endl;
c154c8a4 1717 }
288f4aa9 1718 catch(...) {
e6a9dde5 1719 g_log<<Logger::Error<<"Any other exception in a resolver context "<< makeLoginfo(dc) <<endl;
288f4aa9 1720 }
3ddb9247 1721
ec6eacbc 1722 g_stats.maxMThreadStackUsage = max(MT->getMaxStackUsage(), g_stats.maxMThreadStackUsage);
288f4aa9
BH
1723}
1724
d187038c 1725static void makeControlChannelSocket(int processNum=-1)
1d5b3ce6 1726{
2d733c0f 1727 string sockname=::arg()["socket-dir"]+"/"+s_programname;
677e2a46 1728 if(processNum >= 0)
335da0ba 1729 sockname += "."+std::to_string(processNum);
677e2a46 1730 sockname+=".controlsocket";
41f7a068 1731 s_rcc.listen(sockname);
3ddb9247 1732
387de317
BH
1733 int sockowner = -1;
1734 int sockgroup = -1;
1735
1736 if (!::arg().isEmpty("socket-group"))
1737 sockgroup=::arg().asGid("socket-group");
1738 if (!::arg().isEmpty("socket-owner"))
1739 sockowner=::arg().asUid("socket-owner");
3ddb9247 1740
f838ad8d
BH
1741 if (sockgroup > -1 || sockowner > -1) {
1742 if(chown(sockname.c_str(), sockowner, sockgroup) < 0) {
1743 unixDie("Failed to chown control socket");
1744 }
1745 }
387de317
BH
1746
1747 // do mode change if socket-mode is given
1748 if(!::arg().isEmpty("socket-mode")) {
1749 mode_t sockmode=::arg().asMode("socket-mode");
34c513f9
RG
1750 if(chmod(sockname.c_str(), sockmode) < 0) {
1751 unixDie("Failed to chmod control socket");
1752 }
387de317 1753 }
1d5b3ce6
BH
1754}
1755
5cc8371b 1756static void getQNameAndSubnet(const std::string& question, DNSName* dnsname, uint16_t* qtype, uint16_t* qclass,
29e6303a 1757 bool& foundECS, EDNSSubnetOpts* ednssubnet, EDNSOptionViewMap* options,
5cc8371b 1758 bool& foundXPF, ComboAddress* xpfSource, ComboAddress* xpfDest)
02b47f43 1759{
59cb4a79 1760 const bool lookForXPF = xpfSource != nullptr && g_xpfRRCode != 0;
5cc8371b
RG
1761 const bool lookForECS = ednssubnet != nullptr;
1762 const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(question.c_str());
02b47f43
RG
1763 size_t questionLen = question.length();
1764 unsigned int consumed=0;
1765 *dnsname=DNSName(question.c_str(), questionLen, sizeof(dnsheader), false, qtype, qclass, &consumed);
1766
1767 size_t pos= sizeof(dnsheader)+consumed+4;
5cc8371b
RG
1768 const size_t headerSize = /* root */ 1 + sizeof(dnsrecordheader);
1769 const uint16_t arcount = ntohs(dh->arcount);
1770
1771 for (uint16_t arpos = 0; arpos < arcount && questionLen > (pos + headerSize) && ((lookForECS && !foundECS) || (lookForXPF && !foundXPF)); arpos++) {
1772 if (question.at(pos) != 0) {
1773 /* not an OPT or a XPF, bye. */
1774 return;
1775 }
1776
1777 pos += 1;
1778 const dnsrecordheader* drh = reinterpret_cast<const dnsrecordheader*>(&question.at(pos));
1779 pos += sizeof(dnsrecordheader);
1780
1781 if (pos >= questionLen) {
1782 return;
1783 }
1784
02b47f43 1785 /* OPT root label (1) followed by type (2) */
5cc8371b 1786 if(lookForECS && ntohs(drh->d_type) == QType::OPT) {
00b8cadc
RG
1787 if (!options) {
1788 char* ecsStart = nullptr;
1789 size_t ecsLen = 0;
5cc8371b
RG
1790 /* we need to pass the record len */
1791 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
1792 if (res == 0 && ecsLen > 4) {
1793 EDNSSubnetOpts eso;
1794 if(getEDNSSubnetOptsFromString(ecsStart + 4, ecsLen - 4, &eso)) {
1795 *ednssubnet=eso;
5cc8371b 1796 foundECS = true;
00b8cadc
RG
1797 }
1798 }
1799 }
1800 else {
5cc8371b
RG
1801 /* we need to pass the record len */
1802 int res = getEDNSOptions(reinterpret_cast<const char*>(&question.at(pos -sizeof(drh->d_clen))), questionLen - pos + (sizeof(drh->d_clen)), *options);
00b8cadc
RG
1803 if (res == 0) {
1804 const auto& it = options->find(EDNSOptionCode::ECS);
29e6303a 1805 if (it != options->end() && !it->second.values.empty() && it->second.values.at(0).content != nullptr && it->second.values.at(0).size > 0) {
00b8cadc 1806 EDNSSubnetOpts eso;
29e6303a 1807 if(getEDNSSubnetOptsFromString(it->second.values.at(0).content, it->second.values.at(0).size, &eso)) {
00b8cadc 1808 *ednssubnet=eso;
5cc8371b 1809 foundECS = true;
00b8cadc
RG
1810 }
1811 }
02b47f43
RG
1812 }
1813 }
1814 }
59cb4a79 1815 else if (lookForXPF && ntohs(drh->d_type) == g_xpfRRCode && ntohs(drh->d_class) == QClass::IN && drh->d_ttl == 0) {
5cc8371b
RG
1816 if ((questionLen - pos) < ntohs(drh->d_clen)) {
1817 return;
1818 }
1819
1820 foundXPF = parseXPFPayload(reinterpret_cast<const char*>(&question.at(pos)), ntohs(drh->d_clen), *xpfSource, xpfDest);
1821 }
1822
1823 pos += ntohs(drh->d_clen);
02b47f43
RG
1824 }
1825}
1826
d187038c 1827static void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
09e6702a 1828{
cd989c87 1829 shared_ptr<TCPConnection> conn=any_cast<shared_ptr<TCPConnection> >(var);
c038218b 1830
879b3f70 1831 if(conn->state==TCPConnection::BYTE0) {
2749c3fe 1832 ssize_t bytes=recv(conn->getFD(), &conn->data[0], 2, 0);
09e6702a 1833 if(bytes==1)
667f7e60 1834 conn->state=TCPConnection::BYTE1;
3ddb9247 1835 if(bytes==2) {
a0aa4f64 1836 conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1];
2749c3fe 1837 conn->data.resize(conn->qlen);
667f7e60
BH
1838 conn->bytesread=0;
1839 conn->state=TCPConnection::GETQUESTION;
09e6702a
BH
1840 }
1841 if(!bytes || bytes < 0) {
bb4bdbaf 1842 t_fdm->removeReadFD(fd);
09e6702a
BH
1843 return;
1844 }
1845 }
667f7e60 1846 else if(conn->state==TCPConnection::BYTE1) {
2749c3fe 1847 ssize_t bytes=recv(conn->getFD(), &conn->data[1], 1, 0);
09e6702a 1848 if(bytes==1) {
667f7e60 1849 conn->state=TCPConnection::GETQUESTION;
a0aa4f64 1850 conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1];
2749c3fe 1851 conn->data.resize(conn->qlen);
667f7e60 1852 conn->bytesread=0;
09e6702a
BH
1853 }
1854 if(!bytes || bytes < 0) {
1855 if(g_logCommonErrors)
e6a9dde5 1856 g_log<<Logger::Error<<"TCP client "<< conn->d_remote.toStringWithPort() <<" disconnected after first byte"<<endl;
bb4bdbaf 1857 t_fdm->removeReadFD(fd);
09e6702a
BH
1858 return;
1859 }
1860 }
667f7e60 1861 else if(conn->state==TCPConnection::GETQUESTION) {
2749c3fe 1862 ssize_t bytes=recv(conn->getFD(), &conn->data[conn->bytesread], conn->qlen - conn->bytesread, 0);
f9d67b41 1863 if(!bytes || bytes < 0 || bytes > std::numeric_limits<std::uint16_t>::max()) {
c0f9be19
RG
1864 if(g_logCommonErrors) {
1865 g_log<<Logger::Error<<"TCP client "<< conn->d_remote.toStringWithPort() <<" disconnected while reading question body"<<endl;
1866 }
bb4bdbaf 1867 t_fdm->removeReadFD(fd);
09e6702a
BH
1868 return;
1869 }
b841314c 1870 conn->bytesread+=(uint16_t)bytes;
667f7e60 1871 if(conn->bytesread==conn->qlen) {
bb4bdbaf 1872 t_fdm->removeReadFD(fd); // should no longer awake ourselves when there is data to read
879b3f70 1873
9a864da4 1874 std::unique_ptr<DNSComboWriter> dc;
09e6702a 1875 try {
9a864da4 1876 dc=std::unique_ptr<DNSComboWriter>(new DNSComboWriter(conn->data, g_now));
09e6702a 1877 }
16ce7f18 1878 catch(const MOADNSException &mde) {
3ddb9247 1879 g_stats.clientParseError++;
4957a608 1880 if(g_logCommonErrors)
e6a9dde5 1881 g_log<<Logger::Error<<"Unable to parse packet from TCP client "<< conn->d_remote.toStringWithPort() <<endl;
4957a608 1882 return;
09e6702a 1883 }
cd989c87
BH
1884 dc->d_tcpConnection = conn; // carry the torch
1885 dc->setSocket(conn->getFD()); // this is the only time a copy is made of the actual fd
09e6702a 1886 dc->d_tcp=true;
5cc8371b
RG
1887 dc->setRemote(conn->d_remote);
1888 dc->setSource(conn->d_remote);
a6147cd2 1889 ComboAddress dest;
d38e2ba9 1890 dest.reset();
a6147cd2 1891 dest.sin4.sin_family = conn->d_remote.sin4.sin_family;
1892 socklen_t len = dest.getSocklen();
1893 getsockname(conn->getFD(), (sockaddr*)&dest, &len); // if this fails, we're ok with it
1894 dc->setLocal(dest);
5cc8371b 1895 dc->setDestination(dest);
33dcceba
RG
1896 DNSName qname;
1897 uint16_t qtype=0;
1898 uint16_t qclass=0;
1899 bool needECS = false;
5cc8371b 1900 bool needXPF = g_XPFAcl.match(conn->d_remote);
67e31ebe 1901 string requestorId;
590388d2 1902 string deviceId;
16bbc6e3 1903 bool logQuery = false;
aa7929a3 1904#ifdef HAVE_PROTOBUF
02b47f43 1905 auto luaconfsLocal = g_luaconfs.getLocal();
63341e8d 1906 if (checkProtobufExport(luaconfsLocal)) {
33dcceba
RG
1907 needECS = true;
1908 }
b773359c 1909 logQuery = t_protobufServers && luaconfsLocal->protobufExportConfig.logQueries;
33dcceba
RG
1910#endif
1911
70fb28d9 1912 if(needECS || needXPF || (t_pdl && (t_pdl->d_gettag_ffi || t_pdl->d_gettag))) {
33dcceba
RG
1913
1914 try {
29e6303a 1915 EDNSOptionViewMap ednsOptions;
5cc8371b 1916 bool xpfFound = false;
b40562da 1917 dc->d_ecsParsed = true;
5cc8371b 1918 dc->d_ecsFound = false;
2749c3fe 1919 getQNameAndSubnet(conn->data, &qname, &qtype, &qclass,
5cc8371b
RG
1920 dc->d_ecsFound, &dc->d_ednssubnet, g_gettagNeedsEDNSOptions ? &ednsOptions : nullptr,
1921 xpfFound, needXPF ? &dc->d_source : nullptr, needXPF ? &dc->d_destination : nullptr);
02b47f43 1922
70fb28d9 1923 if(t_pdl) {
33dcceba 1924 try {
70fb28d9 1925 if (t_pdl->d_gettag_ffi) {
f1c7929a 1926 dc->d_tag = t_pdl->gettag_ffi(dc->d_source, dc->d_ednssubnet.source, dc->d_destination, qname, qtype, &dc->d_policyTags, dc->d_data, ednsOptions, true, requestorId, deviceId, dc->d_ttlCap, dc->d_variable, logQuery);
70fb28d9
RG
1927 }
1928 else if (t_pdl->d_gettag) {
1929 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);
1930 }
33dcceba 1931 }
70fb28d9 1932 catch(const std::exception& e) {
33dcceba 1933 if(g_logCommonErrors)
e6a9dde5 1934 g_log<<Logger::Warning<<"Error parsing a query packet qname='"<<qname<<"' for tag determination, setting tag=0: "<<e.what()<<endl;
33dcceba
RG
1935 }
1936 }
1937 }
70fb28d9 1938 catch(const std::exception& e)
33dcceba
RG
1939 {
1940 if(g_logCommonErrors)
e6a9dde5 1941 g_log<<Logger::Warning<<"Error parsing a query packet for tag determination, setting tag=0: "<<e.what()<<endl;
33dcceba
RG
1942 }
1943 }
f52177c3
RG
1944
1945 const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(&conn->data[0]);
1946
33dcceba 1947#ifdef HAVE_PROTOBUF
b773359c 1948 if(t_protobufServers || t_outgoingProtobufServers) {
67e31ebe 1949 dc->d_requestorId = requestorId;
590388d2 1950 dc->d_deviceId = deviceId;
d61aa945 1951 dc->d_uuid = getUniqueID();
4898a348 1952 }
02b47f43 1953
b773359c 1954 if(t_protobufServers) {
02b47f43 1955 try {
02b47f43 1956
845cbf4c 1957 if (logQuery && !(luaconfsLocal->protobufExportConfig.taggedOnly && dc->d_policyTags.empty())) {
b773359c 1958 protobufLogQuery(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 1959 }
02b47f43
RG
1960 }
1961 catch(std::exception& e) {
1962 if(g_logCommonErrors)
e6a9dde5 1963 g_log<<Logger::Warning<<"Error parsing a TCP query packet for edns subnet: "<<e.what()<<endl;
02b47f43
RG
1964 }
1965 }
aa7929a3 1966#endif
5034517a
RG
1967 if(t_pdl) {
1968 if(t_pdl->ipfilter(dc->d_source, dc->d_destination, *dh)) {
1969 if(!g_quiet)
1970 g_log<<Logger::Notice<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] DROPPED TCP question from "<<dc->d_source.toStringWithPort()<<(dc->d_source != dc->d_remote ? " (via "+dc->d_remote.toStringWithPort()+")" : "")<<" based on policy"<<endl;
1971 g_stats.policyDrops++;
1972 return;
1973 }
1974 }
1975
879b3f70 1976 if(dc->d_mdp.d_header.qr) {
048f5db6 1977 g_stats.ignoredCount++;
c0f9be19
RG
1978 if(g_logCommonErrors) {
1979 g_log<<Logger::Error<<"Ignoring answer from TCP client "<< dc->getRemote() <<" on server socket!"<<endl;
1980 }
4957a608 1981 return;
879b3f70 1982 }
3abcdab2 1983 if(dc->d_mdp.d_header.opcode) {
048f5db6 1984 g_stats.ignoredCount++;
c0f9be19
RG
1985 if(g_logCommonErrors) {
1986 g_log<<Logger::Error<<"Ignoring non-query opcode from TCP client "<< dc->getRemote() <<" on server socket!"<<endl;
1987 }
c0f9be19
RG
1988 return;
1989 }
1990 else if (dh->qdcount == 0) {
1991 g_stats.emptyQueriesCount++;
1992 if(g_logCommonErrors) {
1993 g_log<<Logger::Error<<"Ignoring empty (qdcount == 0) query from "<< dc->getRemote() <<" on server socket!"<<endl;
1994 }
3abcdab2
PD
1995 return;
1996 }
09e6702a 1997 else {
4957a608
BH
1998 ++g_stats.qcounter;
1999 ++g_stats.tcpqcounter;
9a864da4 2000 MT->makeThread(startDoResolve, dc.release()); // deletes dc, will set state to BYTE0 again
4957a608 2001 return;
09e6702a
BH
2002 }
2003 }
2004 }
2005}
2006
6dcd28c3 2007//! Handle new incoming TCP connection
d187038c 2008static void handleNewTCPQuestion(int fd, FDMultiplexer::funcparam_t& )
09e6702a 2009{
37d3f960 2010 ComboAddress addr;
09e6702a 2011 socklen_t addrlen=sizeof(addr);
a683e8bd 2012 int newsock=accept(fd, (struct sockaddr*)&addr, &addrlen);
b841314c 2013 if(newsock>=0) {
85c32340
BH
2014 if(MT->numProcesses() > g_maxMThreads) {
2015 g_stats.overCapacityDrops++;
a7b68ae7
RG
2016 try {
2017 closesocket(newsock);
2018 }
2019 catch(const PDNSException& e) {
e6a9dde5 2020 g_log<<Logger::Error<<"Error closing TCP socket after an over capacity drop: "<<e.reason<<endl;
a7b68ae7 2021 }
85c32340
BH
2022 return;
2023 }
2024
92011b8f 2025 if(t_remotes)
2026 t_remotes->push_back(addr);
49a699c4 2027 if(t_allowFrom && !t_allowFrom->match(&addr)) {
3ddb9247 2028 if(!g_quiet)
e6a9dde5 2029 g_log<<Logger::Error<<"["<<MT->getTid()<<"] dropping TCP query from "<<addr.toString()<<", address not matched by allow-from"<<endl;
2914b022 2030
09e6702a 2031 g_stats.unauthorizedTCP++;
a7b68ae7
RG
2032 try {
2033 closesocket(newsock);
2034 }
2035 catch(const PDNSException& e) {
e6a9dde5 2036 g_log<<Logger::Error<<"Error closing TCP socket after an ACL drop: "<<e.reason<<endl;
a7b68ae7 2037 }
09e6702a
BH
2038 return;
2039 }
bd0289fc 2040 if(g_maxTCPPerClient && t_tcpClientCounts->count(addr) && (*t_tcpClientCounts)[addr] >= g_maxTCPPerClient) {
09e6702a 2041 g_stats.tcpClientOverflow++;
a7b68ae7
RG
2042 try {
2043 closesocket(newsock); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
2044 }
2045 catch(const PDNSException& e) {
e6a9dde5 2046 g_log<<Logger::Error<<"Error closing TCP socket after an overflow drop: "<<e.reason<<endl;
a7b68ae7 2047 }
09e6702a
BH
2048 return;
2049 }
3ddb9247 2050
3897b9e1 2051 setNonBlocking(newsock);
f26bf547 2052 std::shared_ptr<TCPConnection> tc = std::make_shared<TCPConnection>(newsock, addr);
cd989c87 2053 tc->state=TCPConnection::BYTE0;
3ddb9247 2054
27ae2e3c
RG
2055 struct timeval ttd;
2056 Utility::gettimeofday(&ttd, 0);
2057 ttd.tv_sec += g_tcpTimeout;
c038218b 2058
27ae2e3c 2059 t_fdm->addReadFD(tc->getFD(), handleRunningTCPQuestion, tc, &ttd);
09e6702a
BH
2060 }
2061}
3ddb9247 2062
d187038c 2063static string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fromaddr, const ComboAddress& destaddr, struct timeval tv, int fd)
1bc3c142 2064{
183eb877 2065 gettimeofday(&g_now, 0);
b71b60ee 2066 struct timeval diff = g_now - tv;
2067 double delta=(diff.tv_sec*1000 + diff.tv_usec/1000.0);
183eb877 2068
22cf1fda 2069 if(tv.tv_sec && delta > 1000.0) {
b71b60ee 2070 g_stats.tooOldDrops++;
2071 return 0;
2072 }
2073
1bc3c142 2074 ++g_stats.qcounter;
d7f10541
BH
2075 if(fromaddr.sin4.sin_family==AF_INET6)
2076 g_stats.ipv6qcounter++;
1bc3c142
BH
2077
2078 string response;
93f0da94 2079 const struct dnsheader* dh = (struct dnsheader*)question.c_str();
49a3500d 2080 unsigned int ctag=0;
f57486f1 2081 uint32_t qhash = 0;
12aff2e5 2082 bool needECS = false;
5cc8371b 2083 bool needXPF = g_XPFAcl.match(fromaddr);
02b47f43 2084 std::vector<std::string> policyTags;
5fd2577f 2085 LuaContext::LuaObject data;
5cc8371b
RG
2086 ComboAddress source = fromaddr;
2087 ComboAddress destination = destaddr;
67e31ebe 2088 string requestorId;
590388d2 2089 string deviceId;
16bbc6e3 2090 bool logQuery = false;
12aff2e5 2091#ifdef HAVE_PROTOBUF
02b47f43 2092 boost::uuids::uuid uniqueId;
02b47f43 2093 auto luaconfsLocal = g_luaconfs.getLocal();
63341e8d 2094 if (checkProtobufExport(luaconfsLocal)) {
d61aa945 2095 uniqueId = getUniqueID();
02b47f43 2096 needECS = true;
63341e8d 2097 } else if (checkOutgoingProtobufExport(luaconfsLocal)) {
d61aa945 2098 uniqueId = getUniqueID();
02b47f43 2099 }
b773359c
RG
2100 logQuery = t_protobufServers && luaconfsLocal->protobufExportConfig.logQueries;
2101 bool logResponse = t_protobufServers && luaconfsLocal->protobufExportConfig.logResponses;
12aff2e5 2102#endif
b40562da
RG
2103 EDNSSubnetOpts ednssubnet;
2104 bool ecsFound = false;
2105 bool ecsParsed = false;
08b02366
RG
2106 uint16_t ecsBegin = 0;
2107 uint16_t ecsEnd = 0;
70fb28d9
RG
2108 uint32_t ttlCap = std::numeric_limits<uint32_t>::max();
2109 bool variable = false;
1bc3c142 2110 try {
02b47f43
RG
2111 DNSName qname;
2112 uint16_t qtype=0;
2113 uint16_t qclass=0;
1bc3c142 2114 uint32_t age;
c15ff3df 2115 bool qnameParsed=false;
8f7473d7 2116#ifdef MALLOC_TRACE
2117 /*
2118 static uint64_t last=0;
2119 if(!last)
2120 g_mtracer->clearAllocators();
2121 cout<<g_mtracer->getAllocs()-last<<" "<<g_mtracer->getNumOut()<<" -- BEGIN TRACE"<<endl;
2122 last=g_mtracer->getAllocs();
2123 cout<<g_mtracer->topAllocatorsString()<<endl;
2124 g_mtracer->clearAllocators();
2125 */
2126#endif
55a1378f 2127
70fb28d9 2128 if(needECS || needXPF || (t_pdl && (t_pdl->d_gettag || t_pdl->d_gettag_ffi))) {
b2eacd67 2129 try {
29e6303a 2130 EDNSOptionViewMap ednsOptions;
5cc8371b
RG
2131 bool xpfFound = false;
2132
2133 ecsFound = false;
2134
2135 getQNameAndSubnet(question, &qname, &qtype, &qclass,
2136 ecsFound, &ednssubnet, g_gettagNeedsEDNSOptions ? &ednsOptions : nullptr,
2137 xpfFound, needXPF ? &source : nullptr, needXPF ? &destination : nullptr);
2138
c15ff3df
RG
2139 qnameParsed = true;
2140 ecsParsed = true;
12aff2e5 2141
70fb28d9 2142 if(t_pdl) {
12aff2e5 2143 try {
70fb28d9 2144 if (t_pdl->d_gettag_ffi) {
f1c7929a 2145 ctag = t_pdl->gettag_ffi(source, ednssubnet.source, destination, qname, qtype, &policyTags, data, ednsOptions, false, requestorId, deviceId, ttlCap, variable, logQuery);
70fb28d9
RG
2146 }
2147 else if (t_pdl->d_gettag) {
2148 ctag = t_pdl->gettag(source, ednssubnet.source, destination, qname, qtype, &policyTags, data, ednsOptions, false, requestorId, deviceId);
2149 }
12aff2e5 2150 }
70fb28d9 2151 catch(const std::exception& e) {
12aff2e5 2152 if(g_logCommonErrors)
e6a9dde5 2153 g_log<<Logger::Warning<<"Error parsing a query packet qname='"<<qname<<"' for tag determination, setting tag=0: "<<e.what()<<endl;
12aff2e5 2154 }
8ea8c302 2155 }
b2eacd67 2156 }
70fb28d9 2157 catch(const std::exception& e)
b2eacd67 2158 {
2159 if(g_logCommonErrors)
e6a9dde5 2160 g_log<<Logger::Warning<<"Error parsing a query packet for tag determination, setting tag=0: "<<e.what()<<endl;
12aff2e5 2161 }
12ce523e 2162 }
3ddb9247 2163
02b47f43 2164 bool cacheHit = false;
1fbc6dc5 2165 boost::optional<RecProtoBufMessage> pbMessage(boost::none);
02b47f43 2166#ifdef HAVE_PROTOBUF
b773359c 2167 if (t_protobufServers) {
d362f7c1 2168 pbMessage = RecProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType::Response);
c165308b 2169 pbMessage->setServerIdentity(SyncRes::s_serverID);
845cbf4c 2170 if (logQuery && !(luaconfsLocal->protobufExportConfig.taggedOnly && policyTags.empty())) {
b773359c 2171 protobufLogQuery(luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, uniqueId, source, destination, ednssubnet.source, false, dh->id, question.size(), qname, qtype, qclass, policyTags, requestorId, deviceId);
b790ef3d 2172 }
d9d3f9c1
RG
2173 }
2174#endif /* HAVE_PROTOBUF */
02b47f43 2175
70fb28d9
RG
2176 /* It might seem like a good idea to skip the packet cache lookup if we know that the answer is not cacheable,
2177 but it means that the hash would not be computed. If some script decides at a later time to mark back the answer
2178 as cacheable we would cache it with a wrong tag, so better safe than sorry. */
8467ec26 2179 vState valState;
c15ff3df 2180 if (qnameParsed) {
08b02366 2181 cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, qtype, qclass, g_now.tv_sec, &response, &age, &valState, &qhash, &ecsBegin, &ecsEnd, pbMessage ? &(*pbMessage) : nullptr));
c15ff3df
RG
2182 }
2183 else {
08b02366 2184 cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, &qtype, &qclass, g_now.tv_sec, &response, &age, &valState, &qhash, &ecsBegin, &ecsEnd, pbMessage ? &(*pbMessage) : nullptr));
c15ff3df
RG
2185 }
2186
d9d3f9c1 2187 if (cacheHit) {
8467ec26
KM
2188 if(valState == Bogus) {
2189 if(t_bogusremotes)
2190 t_bogusremotes->push_back(source);
2191 if(t_bogusqueryring)
2192 t_bogusqueryring->push_back(make_pair(qname, qtype));
2193 }
2194
d9d3f9c1 2195#ifdef HAVE_PROTOBUF
b773359c 2196 if(t_protobufServers && logResponse && !(luaconfsLocal->protobufExportConfig.taggedOnly && pbMessage->getAppliedPolicy().empty() && pbMessage->getPolicyTags().empty())) {
5cc8371b 2197 Netmask requestorNM(source, source.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
e1c8a4bb 2198 const ComboAddress& requestor = requestorNM.getMaskedNetwork();
d362f7c1
RG
2199 pbMessage->update(uniqueId, &requestor, &destination, false, dh->id);
2200 pbMessage->setEDNSSubnet(ednssubnet.source, ednssubnet.source.isIpv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
2201 pbMessage->setQueryTime(g_now.tv_sec, g_now.tv_usec);
2202 pbMessage->setRequestorId(requestorId);
2203 pbMessage->setDeviceId(deviceId);
b773359c 2204 protobufLogResponse(*pbMessage);
02b47f43 2205 }
d9d3f9c1 2206#endif /* HAVE_PROTOBUF */
49a3500d 2207 if(!g_quiet)
e6a9dde5 2208 g_log<<Logger::Notice<<t_id<< " question answered from packet cache tag="<<ctag<<" from "<<source.toStringWithPort()<<(source != fromaddr ? " (via "+fromaddr.toStringWithPort()+")" : "")<<endl;
8f7473d7 2209
1bc3c142
BH
2210 g_stats.packetCacheHits++;
2211 SyncRes::s_queries++;
2212 ageDNSPacket(response, age);
b71b60ee 2213 struct msghdr msgh;
2214 struct iovec iov;
2215 char cbuf[256];
2216 fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)response.c_str(), response.length(), const_cast<ComboAddress*>(&fromaddr));
2c0af54f
PD
2217 msgh.msg_control=NULL;
2218
cbc03320 2219 if(g_fromtosockets.count(fd)) {
fbe2a2e0 2220 addCMsgSrcAddr(&msgh, cbuf, &destaddr, 0);
b71b60ee 2221 }
cbc03320 2222 if(sendmsg(fd, &msgh, 0) < 0 && g_logCommonErrors)
e6a9dde5 2223 g_log<<Logger::Warning<<"Sending UDP reply to client "<<source.toStringWithPort()<<(source != fromaddr ? " (via "+fromaddr.toStringWithPort()+")" : "")<<" failed with: "<<strerror(errno)<<endl;
b71b60ee 2224
97bee66d 2225 if(response.length() >= sizeof(struct dnsheader)) {
dd079764
RG
2226 struct dnsheader tmpdh;
2227 memcpy(&tmpdh, response.c_str(), sizeof(tmpdh));
5cc8371b 2228 updateResponseStats(tmpdh.rcode, source, response.length(), 0, 0);
97bee66d 2229 }
08f3f638 2230 g_stats.avgLatencyUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyUsec + 0.0; // we assume 0 usec
19178da9 2231 g_stats.avgLatencyOursUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyOursUsec + 0.0; // we assume 0 usec
1bc3c142
BH
2232 return 0;
2233 }
3ddb9247 2234 }
1bc3c142 2235 catch(std::exception& e) {
e6a9dde5 2236 g_log<<Logger::Error<<"Error processing or aging answer packet: "<<e.what()<<endl;
1bc3c142
BH
2237 return 0;
2238 }
3ddb9247 2239
f26bf547 2240 if(t_pdl) {
5cc8371b 2241 if(t_pdl->ipfilter(source, destination, *dh)) {
4ea94941 2242 if(!g_quiet)
e6a9dde5 2243 g_log<<Logger::Notice<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] DROPPED question from "<<source.toStringWithPort()<<(source != fromaddr ? " (via "+fromaddr.toStringWithPort()+")" : "")<<" based on policy"<<endl;
4ea94941 2244 g_stats.policyDrops++;
2245 return 0;
2246 }
2247 }
2248
1bc3c142 2249 if(MT->numProcesses() > g_maxMThreads) {
461df9d2 2250 if(!g_quiet)
e6a9dde5 2251 g_log<<Logger::Notice<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] DROPPED question from "<<source.toStringWithPort()<<(source != fromaddr ? " (via "+fromaddr.toStringWithPort()+")" : "")<<", over capacity"<<endl;
461df9d2 2252
1bc3c142
BH
2253 g_stats.overCapacityDrops++;
2254 return 0;
2255 }
3ddb9247 2256
9a864da4 2257 auto dc = std::unique_ptr<DNSComboWriter>(new DNSComboWriter(question, g_now, std::move(policyTags), std::move(data)));
1bc3c142 2258 dc->setSocket(fd);
49a3500d 2259 dc->d_tag=ctag;
e9f63d47 2260 dc->d_qhash=qhash;
5cc8371b
RG
2261 dc->setRemote(fromaddr);
2262 dc->setSource(source);
b71b60ee 2263 dc->setLocal(destaddr);
5cc8371b 2264 dc->setDestination(destination);
1bc3c142 2265 dc->d_tcp=false;
b40562da
RG
2266 dc->d_ecsFound = ecsFound;
2267 dc->d_ecsParsed = ecsParsed;
08b02366
RG
2268 dc->d_ecsBegin = ecsBegin;
2269 dc->d_ecsEnd = ecsEnd;
b40562da 2270 dc->d_ednssubnet = ednssubnet;
70fb28d9
RG
2271 dc->d_ttlCap = ttlCap;
2272 dc->d_variable = variable;
aa7929a3 2273#ifdef HAVE_PROTOBUF
b773359c 2274 if (t_protobufServers || t_outgoingProtobufServers) {
5164bac3 2275 dc->d_uuid = std::move(uniqueId);
d9d3f9c1 2276 }
67e31ebe 2277 dc->d_requestorId = requestorId;
590388d2 2278 dc->d_deviceId = deviceId;
aa7929a3
RG
2279#endif
2280
9a864da4 2281 MT->makeThread(startDoResolve, (void*) dc.release()); // deletes dc
1bc3c142 2282 return 0;
3ddb9247
PD
2283}
2284
b71b60ee 2285
d187038c 2286static void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var)
5db529f8 2287{
a683e8bd 2288 ssize_t len;
12c2f2b9 2289 static const size_t maxIncomingQuerySize = 512;
04896b99 2290 static thread_local std::string data;
5db529f8 2291 ComboAddress fromaddr;
b71b60ee 2292 struct msghdr msgh;
2293 struct iovec iov;
2294 char cbuf[256];
390f1dab 2295 bool firstQuery = true;
b71b60ee 2296
c0a00acd
RG
2297 for(size_t queriesCounter = 0; queriesCounter < s_maxUDPQueriesPerRound; queriesCounter++) {
2298 data.resize(maxIncomingQuerySize);
2299 fromaddr.sin6.sin6_family=AF_INET6; // this makes sure fromaddr is big enough
2300 fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), &data[0], data.size(), &fromaddr);
b71b60ee 2301
c0a00acd 2302 if((len=recvmsg(fd, &msgh, 0)) >= 0) {
390f1dab 2303
c0a00acd 2304 firstQuery = false;
390f1dab 2305
c0a00acd
RG
2306 if (static_cast<size_t>(len) < sizeof(dnsheader)) {
2307 g_stats.ignoredCount++;
2308 if (!g_quiet) {
2309 g_log<<Logger::Error<<"Ignoring too-short ("<<std::to_string(len)<<") query from "<<fromaddr.toString()<<endl;
2310 }
2311 return;
04896b99 2312 }
04896b99 2313
c0a00acd
RG
2314 if (msgh.msg_flags & MSG_TRUNC) {
2315 g_stats.truncatedDrops++;
2316 if (!g_quiet) {
2317 g_log<<Logger::Error<<"Ignoring truncated query from "<<fromaddr.toString()<<endl;
2318 }
2319 return;
ba892c7f 2320 }
b23b8614 2321
c0a00acd
RG
2322 if(t_remotes) {
2323 t_remotes->push_back(fromaddr);
2324 }
81859ba5 2325
c0a00acd
RG
2326 if(t_allowFrom && !t_allowFrom->match(&fromaddr)) {
2327 if(!g_quiet) {
2328 g_log<<Logger::Error<<"["<<MT->getTid()<<"] dropping UDP query from "<<fromaddr.toString()<<", address not matched by allow-from"<<endl;
2329 }
3ddb9247 2330
c0a00acd
RG
2331 g_stats.unauthorizedUDP++;
2332 return;
5db529f8 2333 }
c0a00acd
RG
2334 BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_port) == offsetof(sockaddr_in6, sin6_port));
2335 if(!fromaddr.sin4.sin_port) { // also works for IPv6
2336 if(!g_quiet) {
2337 g_log<<Logger::Error<<"["<<MT->getTid()<<"] dropping UDP query from "<<fromaddr.toStringWithPort()<<", can't deal with port 0"<<endl;
2338 }
2339
2340 g_stats.clientParseError++; // not quite the best place to put it, but needs to go somewhere
2341 return;
3abcdab2 2342 }
c0a00acd
RG
2343
2344 try {
2345 data.resize(static_cast<size_t>(len));
2346 dnsheader* dh=(dnsheader*)&data[0];
2347
2348 if(dh->qr) {
2349 g_stats.ignoredCount++;
2350 if(g_logCommonErrors) {
2351 g_log<<Logger::Error<<"Ignoring answer from "<<fromaddr.toString()<<" on server socket!"<<endl;
2352 }
2353 }
2354 else if(dh->opcode) {
2355 g_stats.ignoredCount++;
2356 if(g_logCommonErrors) {
2357 g_log<<Logger::Error<<"Ignoring non-query opcode "<<dh->opcode<<" from "<<fromaddr.toString()<<" on server socket!"<<endl;
2358 }
a6147cd2 2359 }
c0f9be19
RG
2360 else if (dh->qdcount == 0) {
2361 g_stats.emptyQueriesCount++;
2362 if(g_logCommonErrors) {
2363 g_log<<Logger::Error<<"Ignoring empty (qdcount == 0) query from "<<fromaddr.toString()<<" on server socket!"<<endl;
2364 }
2365 }
a6147cd2 2366 else {
c0a00acd
RG
2367 struct timeval tv={0,0};
2368 HarvestTimestamp(&msgh, &tv);
2369 ComboAddress dest;
2370 dest.reset(); // this makes sure we ignore this address if not returned by recvmsg above
2371 auto loc = rplookup(g_listenSocketsAddresses, fd);
2372 if(HarvestDestinationAddress(&msgh, &dest)) {
2373 // but.. need to get port too
2374 if(loc) {
2375 dest.sin4.sin_port = loc->sin4.sin_port;
2376 }
a6147cd2 2377 }
2378 else {
c0a00acd
RG
2379 if(loc) {
2380 dest = *loc;
2381 }
2382 else {
2383 dest.sin4.sin_family = fromaddr.sin4.sin_family;
2384 socklen_t slen = dest.getSocklen();
2385 getsockname(fd, (sockaddr*)&dest, &slen); // if this fails, we're ok with it
2386 }
2387 }
2388
2389 if(g_weDistributeQueries) {
2390 distributeAsyncFunction(data, boost::bind(doProcessUDPQuestion, data, fromaddr, dest, tv, fd));
2391 }
2392 else {
144040be 2393 ++s_threadInfos[t_id].numberOfDistributedQueries;
c0a00acd 2394 doProcessUDPQuestion(data, fromaddr, dest, tv, fd);
a6147cd2 2395 }
2396 }
c0a00acd 2397 }
16ce7f18 2398 catch(const MOADNSException &mde) {
c0a00acd
RG
2399 g_stats.clientParseError++;
2400 if(g_logCommonErrors) {
2401 g_log<<Logger::Error<<"Unable to parse packet from remote UDP client "<<fromaddr.toString() <<": "<<mde.what()<<endl;
2402 }
2403 }
2404 catch(const std::runtime_error& e) {
2405 g_stats.clientParseError++;
2406 if(g_logCommonErrors) {
2407 g_log<<Logger::Error<<"Unable to parse packet from remote UDP client "<<fromaddr.toString() <<": "<<e.what()<<endl;
2408 }
5db529f8
BH
2409 }
2410 }
c0a00acd
RG
2411 else {
2412 // cerr<<t_id<<" had error: "<<stringerror()<<endl;
2413 if(firstQuery && errno == EAGAIN) {
2414 g_stats.noPacketError++;
2415 }
390f1dab 2416
c0a00acd
RG
2417 break;
2418 }
ac0e821b 2419 }
5db529f8
BH
2420}
2421
adb6cd72 2422static void makeTCPServerSockets(deferredAdd_t& deferredAdds, std::set<int>& tcpSockets)
9c495589 2423{
37d3f960 2424 int fd;
f28307ad 2425 vector<string>locals;
2e3d8a19 2426 stringtok(locals,::arg()["local-address"]," ,");
9c495589 2427
f28307ad 2428 if(locals.empty())
3f81d239 2429 throw PDNSException("No local address specified");
3ddb9247 2430
f28307ad 2431 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
32252594
BH
2432 ServiceTuple st;
2433 st.port=::arg().asNum("local-port");
2434 parseService(*i, st);
3ddb9247 2435
32252594
BH
2436 ComboAddress sin;
2437
d38e2ba9 2438 sin.reset();
37d3f960 2439 sin.sin4.sin_family = AF_INET;
32252594 2440 if(!IpToU32(st.host, (uint32_t*)&sin.sin4.sin_addr.s_addr)) {
37d3f960 2441 sin.sin6.sin6_family = AF_INET6;
f71bc087 2442 if(makeIPv6sockaddr(st.host, &sin.sin6) < 0)
3ddb9247 2443 throw PDNSException("Unable to resolve local address for TCP server on '"+ st.host +"'");
37d3f960
BH
2444 }
2445
2446 fd=socket(sin.sin6.sin6_family, SOCK_STREAM, 0);
3ddb9247 2447 if(fd<0)
3f81d239 2448 throw PDNSException("Making a TCP server socket for resolver: "+stringerror());
f28307ad 2449
3897b9e1 2450 setCloseOnExec(fd);
a903b39c 2451
f28307ad 2452 int tmp=1;
810ff705 2453 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof tmp)<0) {
e6a9dde5 2454 g_log<<Logger::Error<<"Setsockopt failed for TCP listening socket"<<endl;
c8ddb7c2 2455 exit(1);
f28307ad 2456 }
0dfa94ab 2457 if(sin.sin6.sin6_family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp)) < 0) {
e6a9dde5 2458 g_log<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
0dfa94ab 2459 }
2460
c8ddb7c2 2461#ifdef TCP_DEFER_ACCEPT
38ac0821 2462 if(setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &tmp, sizeof tmp) >= 0) {
37d3f960 2463 if(i==locals.begin())
377602e3 2464 g_log<<Logger::Info<<"Enabled TCP data-ready filter for (slight) DoS protection"<<endl;
c8ddb7c2
BH
2465 }
2466#endif
2467
fec7dd5a
SS
2468 if( ::arg().mustDo("non-local-bind") )
2469 Utility::setBindAny(AF_INET, fd);
2470
2332f42d 2471#ifdef SO_REUSEPORT
810ff705
RG
2472 if(g_reusePort) {
2473 if(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &tmp, sizeof(tmp)) < 0)
2332f42d 2474 throw PDNSException("SO_REUSEPORT: "+stringerror());
2475 }
2476#endif
2477
0735b17e
RG
2478 if (::arg().asNum("tcp-fast-open") > 0) {
2479#ifdef TCP_FASTOPEN
2480 int fastOpenQueueSize = ::arg().asNum("tcp-fast-open");
2481 if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &fastOpenQueueSize, sizeof fastOpenQueueSize) < 0) {
e6a9dde5 2482 g_log<<Logger::Error<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno)<<endl;
0735b17e
RG
2483 }
2484#else
e6a9dde5 2485 g_log<<Logger::Warning<<"TCP Fast Open configured but not supported for listening socket"<<endl;
0735b17e
RG
2486#endif
2487 }
2488
32252594 2489 sin.sin4.sin_port = htons(st.port);
a683e8bd 2490 socklen_t socklen=sin.sin4.sin_family==AF_INET ? sizeof(sin.sin4) : sizeof(sin.sin6);
3ddb9247 2491 if (::bind(fd, (struct sockaddr *)&sin, socklen )<0)
3f81d239 2492 throw PDNSException("Binding TCP server socket for "+ st.host +": "+stringerror());
3ddb9247 2493
3897b9e1 2494 setNonBlocking(fd);
49a699c4 2495 setSocketSendBuffer(fd, 65000);
37d3f960 2496 listen(fd, 128);
b243ca3b 2497 deferredAdds.push_back(make_pair(fd, handleNewTCPQuestion));
adb6cd72
RG
2498 tcpSockets.insert(fd);
2499
84433b79 2500 // we don't need to update g_listenSocketsAddresses since it doesn't work for TCP/IP:
2501 // - fd is not that which we know here, but returned from accept()
3ddb9247 2502 if(sin.sin4.sin_family == AF_INET)
377602e3 2503 g_log<<Logger::Info<<"Listening for TCP queries on "<< sin.toString() <<":"<<st.port<<endl;
aa136564 2504 else
377602e3 2505 g_log<<Logger::Info<<"Listening for TCP queries on ["<< sin.toString() <<"]:"<<st.port<<endl;
f28307ad 2506 }
9c495589
BH
2507}
2508
b243ca3b 2509static void makeUDPServerSockets(deferredAdd_t& deferredAdds)
288f4aa9 2510{
fec7dd5a 2511 int one=1;
f28307ad 2512 vector<string>locals;
2e3d8a19 2513 stringtok(locals,::arg()["local-address"]," ,");
288f4aa9 2514
f28307ad 2515 if(locals.empty())
3f81d239 2516 throw PDNSException("No local address specified");
3ddb9247 2517
f28307ad 2518 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
32252594
BH
2519 ServiceTuple st;
2520 st.port=::arg().asNum("local-port");
2521 parseService(*i, st);
2522
37d3f960 2523 ComboAddress sin;
996c89cc 2524
d38e2ba9 2525 sin.reset();
37d3f960 2526 sin.sin4.sin_family = AF_INET;
32252594 2527 if(!IpToU32(st.host.c_str() , (uint32_t*)&sin.sin4.sin_addr.s_addr)) {
37d3f960 2528 sin.sin6.sin6_family = AF_INET6;
f71bc087 2529 if(makeIPv6sockaddr(st.host, &sin.sin6) < 0)
3ddb9247 2530 throw PDNSException("Unable to resolve local address for UDP server on '"+ st.host +"'");
37d3f960 2531 }
3ddb9247 2532
bb4bdbaf 2533 int fd=socket(sin.sin4.sin_family, SOCK_DGRAM, 0);
d3b4137e 2534 if(fd < 0) {
3f81d239 2535 throw PDNSException("Making a UDP server socket for resolver: "+netstringerror());
d3b4137e 2536 }
915b0c39 2537 if (!setSocketTimestamps(fd))
e6a9dde5 2538 g_log<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
0dfa94ab 2539
b71b60ee 2540 if(IsAnyAddress(sin)) {
cbc03320 2541 if(sin.sin4.sin_family == AF_INET)
2542 if(!setsockopt(fd, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one))) // linux supports this, so why not - might fail on other systems
2543 g_fromtosockets.insert(fd);
757d3179 2544#ifdef IPV6_RECVPKTINFO
cbc03320 2545 if(sin.sin4.sin_family == AF_INET6)
2546 if(!setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)))
2547 g_fromtosockets.insert(fd);
757d3179 2548#endif
0dfa94ab 2549 if(sin.sin6.sin6_family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0) {
e6a9dde5 2550 g_log<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
0dfa94ab 2551 }
b71b60ee 2552 }
fec7dd5a
SS
2553 if( ::arg().mustDo("non-local-bind") )
2554 Utility::setBindAny(AF_INET6, fd);
2555
3897b9e1 2556 setCloseOnExec(fd);
a903b39c 2557
4e9a20e6 2558 setSocketReceiveBuffer(fd, 250000);
32252594 2559 sin.sin4.sin_port = htons(st.port);
37d3f960 2560
2332f42d 2561
2573d4a6 2562#ifdef SO_REUSEPORT
810ff705 2563 if(g_reusePort) {
2332f42d 2564 if(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
2565 throw PDNSException("SO_REUSEPORT: "+stringerror());
2566 }
2567#endif
a683e8bd 2568 socklen_t socklen=sin.getSocklen();
3ddb9247 2569 if (::bind(fd, (struct sockaddr *)&sin, socklen)<0)
335da0ba 2570 throw PDNSException("Resolver binding to server socket on port "+ std::to_string(st.port) +" for "+ st.host+": "+stringerror());
3ddb9247 2571
3897b9e1 2572 setNonBlocking(fd);
c2136bf0 2573
b243ca3b 2574 deferredAdds.push_back(make_pair(fd, handleNewUDPQuestion));
40a3dd64 2575 g_listenSocketsAddresses[fd]=sin; // this is written to only from the startup thread, not from the workers
3ddb9247 2576 if(sin.sin4.sin_family == AF_INET)
377602e3 2577 g_log<<Logger::Info<<"Listening for UDP queries on "<< sin.toString() <<":"<<st.port<<endl;
aa136564 2578 else
377602e3 2579 g_log<<Logger::Info<<"Listening for UDP queries on ["<< sin.toString() <<"]:"<<st.port<<endl;
f28307ad 2580 }
c836dc19 2581}
caa6eefa 2582
d187038c 2583static void daemonize(void)
c836dc19
BH
2584{
2585 if(fork())
2586 exit(0); // bye bye
3ddb9247
PD
2587
2588 setsid();
c836dc19 2589
27a5ead5 2590 int i=open("/dev/null",O_RDWR); /* open stdin */
3ddb9247 2591 if(i < 0)
e6a9dde5 2592 g_log<<Logger::Critical<<"Unable to open /dev/null: "<<stringerror()<<endl;
27a5ead5
BH
2593 else {
2594 dup2(i,0); /* stdin */
2595 dup2(i,1); /* stderr */
2596 dup2(i,2); /* stderr */
2597 close(i);
2598 }
288f4aa9 2599}
caa6eefa 2600
d187038c 2601static void usr1Handler(int)
c75a6a9e
BH
2602{
2603 statsWanted=true;
2604}
ae1b2e98 2605
d187038c 2606static void usr2Handler(int)
9170fbaf 2607{
f1f34cc2 2608 g_quiet= !g_quiet;
2609 SyncRes::setDefaultLogMode(g_quiet ? SyncRes::LogNone : SyncRes::Log);
2610 ::arg().set("quiet")=g_quiet ? "" : "no";
9170fbaf
BH
2611}
2612
d187038c 2613static void doStats(void)
c75a6a9e 2614{
16beeaa4
BH
2615 static time_t lastOutputTime;
2616 static uint64_t lastQueryCount;
d299d4f5 2617
2618 uint64_t cacheHits = broadcastAccFunction<uint64_t>(pleaseGetCacheHits);
2619 uint64_t cacheMisses = broadcastAccFunction<uint64_t>(pleaseGetCacheMisses);
3ddb9247 2620
d299d4f5 2621 if(g_stats.qcounter && (cacheHits + cacheMisses) && SyncRes::s_queries && SyncRes::s_outqueries) {
e6a9dde5 2622 g_log<<Logger::Notice<<"stats: "<<g_stats.qcounter<<" questions, "<<
3427fa8a
BH
2623 broadcastAccFunction<uint64_t>(pleaseGetCacheSize)<< " cache entries, "<<
2624 broadcastAccFunction<uint64_t>(pleaseGetNegCacheSize)<<" negative entries, "<<
3ddb9247
PD
2625 (int)((cacheHits*100.0)/(cacheHits+cacheMisses))<<"% cache hits"<<endl;
2626
e6a9dde5 2627 g_log<<Logger::Notice<<"stats: throttle map: "
3427fa8a 2628 << broadcastAccFunction<uint64_t>(pleaseGetThrottleSize) <<", ns speeds: "
3ddb9247 2629 << broadcastAccFunction<uint64_t>(pleaseGetNsSpeedsSize)<<endl;
e6a9dde5
PL
2630 g_log<<Logger::Notice<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%";
2631 g_log<<Logger::Notice<<", "<<(int)(SyncRes::s_throttledqueries*100.0/(SyncRes::s_outqueries+SyncRes::s_throttledqueries))<<"% throttled, "
525b8a7c 2632 <<SyncRes::s_nodelegated<<" no-delegation drops"<<endl;
e6a9dde5 2633 g_log<<Logger::Notice<<"stats: "<<SyncRes::s_tcpoutqueries<<" outgoing tcp connections, "<<
3427fa8a 2634 broadcastAccFunction<uint64_t>(pleaseGetConcurrentQueries)<<" queries running, "<<SyncRes::s_outgoingtimeouts<<" outgoing timeouts"<<endl;
81883dcc 2635
e6a9dde5 2636 //g_log<<Logger::Notice<<"stats: "<<g_stats.ednsPingMatches<<" ping matches, "<<g_stats.ednsPingMismatches<<" mismatches, "<<
16beeaa4 2637 //g_stats.noPingOutQueries<<" outqueries w/o ping, "<< g_stats.noEdnsOutQueries<<" w/o EDNS"<<endl;
3ddb9247 2638
e6a9dde5 2639 g_log<<Logger::Notice<<"stats: " << broadcastAccFunction<uint64_t>(pleaseGetPacketCacheSize) <<
16beeaa4 2640 " packet cache entries, "<<(int)(100.0*broadcastAccFunction<uint64_t>(pleaseGetPacketCacheHits)/SyncRes::s_queries) << "% packet cache hits"<<endl;
3ddb9247 2641
144040be
RG
2642 size_t idx = 0;
2643 for (const auto& threadInfo : s_threadInfos) {
2644 if(threadInfo.isWorker) {
2645 g_log<<Logger::Notice<<"Thread "<<idx<<" has been distributed "<<threadInfo.numberOfDistributedQueries<<" queries"<<endl;
2646 ++idx;
2647 }
2648 }
2649
16beeaa4
BH
2650 time_t now = time(0);
2651 if(lastOutputTime && lastQueryCount && now != lastOutputTime) {
e6a9dde5 2652 g_log<<Logger::Notice<<"stats: "<< (SyncRes::s_queries - lastQueryCount) / (now - lastOutputTime) <<" qps (average over "<< (now - lastOutputTime) << " seconds)"<<endl;
16beeaa4
BH
2653 }
2654 lastOutputTime = now;
2655 lastQueryCount = SyncRes::s_queries;
c75a6a9e 2656 }
3ddb9247 2657 else if(statsWanted)
e6a9dde5 2658 g_log<<Logger::Notice<<"stats: no stats yet!"<<endl;
7becf07f 2659
c75a6a9e
BH
2660 statsWanted=false;
2661}
c836dc19 2662
29f0b1ce 2663static void houseKeeping(void *)
c836dc19 2664{
e4ae55e5 2665 static thread_local time_t last_rootupdate, last_prune, last_secpoll, last_trustAnchorUpdate{0};
3337c2f7
RG
2666 static thread_local int cleanCounter=0;
2667 static thread_local bool s_running; // houseKeeping can get suspended in secpoll, and be restarted, which makes us do duplicate work
e4ae55e5
PL
2668 auto luaconfsLocal = g_luaconfs.getLocal();
2669
2670 if (last_trustAnchorUpdate == 0 && !luaconfsLocal->trustAnchorFileInfo.fname.empty() && luaconfsLocal->trustAnchorFileInfo.interval != 0) {
2671 // Loading the Lua config file already "refreshed" the TAs
2672 last_trustAnchorUpdate = g_now.tv_sec + luaconfsLocal->trustAnchorFileInfo.interval * 3600;
2673 }
2674
cc59bce6 2675 try {
2676 if(s_running)
2677 return;
2678 s_running=true;
3ddb9247 2679
cc59bce6 2680 struct timeval now;
2681 Utility::gettimeofday(&now, 0);
3ddb9247
PD
2682
2683 if(now.tv_sec - last_prune > (time_t)(5 + t_id)) {
cc59bce6 2684 DTime dt;
2685 dt.setTimeval(now);
a6f7f5fe 2686 t_RC->doPrune(g_maxCacheEntries / g_numThreads); // this function is local to a thread, so fine anyhow
2687 t_packetCache->doPruneTo(g_maxPacketCacheEntries / g_numWorkerThreads);
3ddb9247 2688
a6f7f5fe 2689 SyncRes::pruneNegCache(g_maxCacheEntries / (g_numWorkerThreads * 10));
3ddb9247 2690
cc59bce6 2691 if(!((cleanCounter++)%40)) { // this is a full scan!
2692 time_t limit=now.tv_sec-300;
a712cb56 2693 SyncRes::pruneNSSpeeds(limit);
cc59bce6 2694 }
2695 last_prune=time(0);
d67620e4 2696 }
3ddb9247 2697
cc59bce6 2698 if(now.tv_sec - last_rootupdate > 7200) {
30ee601a 2699 int res = SyncRes::getRootNS(g_now, nullptr);
7836f7b4
PL
2700 if (!res)
2701 last_rootupdate=now.tv_sec;
cc59bce6 2702 }
3ddb9247 2703
b243ca3b 2704 if(isHandlerThread()) {
3ddb9247 2705
cc59bce6 2706 if(now.tv_sec - last_secpoll >= 3600) {
2707 try {
2708 doSecPoll(&last_secpoll);
2709 }
581d4ea3 2710 catch(std::exception& e)
2711 {
e6a9dde5 2712 g_log<<Logger::Error<<"Exception while performing security poll: "<<e.what()<<endl;
581d4ea3 2713 }
47e9b74f 2714 catch(PDNSException& e)
2715 {
e6a9dde5 2716 g_log<<Logger::Error<<"Exception while performing security poll: "<<e.reason<<endl;
47e9b74f 2717 }
d0992a65
CH
2718 catch(ImmediateServFailException &e)
2719 {
e6a9dde5 2720 g_log<<Logger::Error<<"Exception while performing security poll: "<<e.reason<<endl;
d0992a65 2721 }
47e9b74f 2722 catch(...)
2723 {
e6a9dde5 2724 g_log<<Logger::Error<<"Exception while performing security poll"<<endl;
47e9b74f 2725 }
18b73338 2726 }
e4ae55e5
PL
2727
2728 if (!luaconfsLocal->trustAnchorFileInfo.fname.empty() && luaconfsLocal->trustAnchorFileInfo.interval != 0 &&
2729 g_now.tv_sec - last_trustAnchorUpdate >= (luaconfsLocal->trustAnchorFileInfo.interval * 3600)) {
2730 g_log<<Logger::Debug<<"Refreshing Trust Anchors from file"<<endl;
2731 try {
2732 map<DNSName, dsmap_t> dsAnchors;
2733 if (updateTrustAnchorsFromFile(luaconfsLocal->trustAnchorFileInfo.fname, dsAnchors)) {
2734 g_luaconfs.modify([&dsAnchors](LuaConfigItems& lci) {
2735 lci.dsAnchors = dsAnchors;
2736 });
2737 }
2738 last_trustAnchorUpdate = now.tv_sec;
2739 } catch (const PDNSException &pe) {
2740 g_log<<Logger::Error<<"Unable to update Trust Anchors: "<<pe.reason<<endl;
2741 }
2742 }
2743 s_running=false;
d67620e4 2744 }
2745 }
cc59bce6 2746 catch(PDNSException& ae)
2747 {
2748 s_running=false;
e6a9dde5 2749 g_log<<Logger::Error<<"Fatal error in housekeeping thread: "<<ae.reason<<endl;
cc59bce6 2750 throw;
2751 }
779828c4 2752}
d6d5dea7 2753
d187038c 2754static void makeThreadPipes()
49a699c4 2755{
b243ca3b
RG
2756 /* thread 0 is the handler / SNMP, we start at 1 */
2757 for(unsigned int n = 1; n <= (g_numWorkerThreads + g_numDistributorThreads); ++n) {
2758 auto& threadInfos = s_threadInfos.at(n);
2759
49a699c4
BH
2760 int fd[2];
2761 if(pipe(fd) < 0)
2762 unixDie("Creating pipe for inter-thread communications");
3ddb9247 2763
b243ca3b
RG
2764 threadInfos.pipes.readToThread = fd[0];
2765 threadInfos.pipes.writeToThread = fd[1];
3ddb9247 2766
49a699c4
BH
2767 if(pipe(fd) < 0)
2768 unixDie("Creating pipe for inter-thread communications");
b243ca3b
RG
2769
2770 threadInfos.pipes.readFromThread = fd[0];
2771 threadInfos.pipes.writeFromThread = fd[1];
3ddb9247 2772
cf8cda18
RG
2773 if(pipe(fd) < 0)
2774 unixDie("Creating pipe for inter-thread communications");
d10307c5 2775
b243ca3b
RG
2776 threadInfos.pipes.readQueriesToThread = fd[0];
2777 threadInfos.pipes.writeQueriesToThread = fd[1];
2778
2779 if (!setNonBlocking(threadInfos.pipes.writeQueriesToThread)) {
d10307c5
RG
2780 unixDie("Making pipe for inter-thread communications non-blocking");
2781 }
49a699c4
BH
2782 }
2783}
2784
00c9b8c1
BH
2785struct ThreadMSG
2786{
2787 pipefunc_t func;
2788 bool wantAnswer;
2789};
2790
b4e76a18 2791void broadcastFunction(const pipefunc_t& func)
49a699c4 2792{
b243ca3b
RG
2793 /* This function might be called by the worker with t_id 0 during startup
2794 for the initialization of ACLs and domain maps. After that it should only
2795 be called by the handler. */
d77abca1 2796
b243ca3b
RG
2797 if (s_threadInfos.empty() && isHandlerThread()) {
2798 /* the handler and distributors will call themselves below, but
2799 during startup we get called while s_threadInfos has not been
2800 populated yet to update the ACL or domain maps, so we need to
2801 handle that case.
2802 */
2803 func();
2804 }
b4e76a18 2805
b243ca3b
RG
2806 unsigned int n = 0;
2807 for (const auto& threadInfo : s_threadInfos) {
49a699c4 2808 if(n++ == t_id) {
b4e76a18 2809 func(); // don't write to ourselves!
49a699c4
BH
2810 continue;
2811 }
3ddb9247 2812
00c9b8c1
BH
2813 ThreadMSG* tmsg = new ThreadMSG();
2814 tmsg->func = func;
2815 tmsg->wantAnswer = true;
b243ca3b 2816 if(write(threadInfo.pipes.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) {
b841314c 2817 delete tmsg;
b243ca3b 2818
49a699c4 2819 unixDie("write to thread pipe returned wrong size or error");
b841314c 2820 }
3ddb9247 2821
49467864 2822 string* resp = nullptr;
b243ca3b 2823 if(read(threadInfo.pipes.readFromThread, &resp, sizeof(resp)) != sizeof(resp))
49a699c4 2824 unixDie("read from thread pipe returned wrong size or error");
3ddb9247 2825
49a699c4 2826 if(resp) {
49a699c4 2827 delete resp;
49467864 2828 resp = nullptr;
49a699c4
BH
2829 }
2830 }
2831}
06ea9015 2832
592d7ade 2833static bool trySendingQueryToWorker(unsigned int target, ThreadMSG* tmsg)
00c9b8c1 2834{
144040be 2835 auto& targetInfo = s_threadInfos[target];
b243ca3b
RG
2836 if(!targetInfo.isWorker) {
2837 g_log<<Logger::Error<<"distributeAsyncFunction() tried to assign a query to a non-worker thread"<<endl;
d77abca1 2838 exit(1);
00c9b8c1 2839 }
d77abca1 2840
b243ca3b 2841 const auto& tps = targetInfo.pipes;
3ddb9247 2842
cf8cda18
RG
2843 ssize_t written = write(tps.writeQueriesToThread, &tmsg, sizeof(tmsg));
2844 if (written > 0) {
2845 if (static_cast<size_t>(written) != sizeof(tmsg)) {
2846 delete tmsg;
2847 unixDie("write to thread pipe returned wrong size or error");
2848 }
2849 }
2850 else {
2851 int error = errno;
cf8cda18 2852 if (error == EAGAIN || error == EWOULDBLOCK) {
592d7ade 2853 return false;
cf8cda18 2854 } else {
592d7ade 2855 delete tmsg;
17634427 2856 unixDie("write to thread pipe returned wrong size or error:" + std::to_string(error));
cf8cda18 2857 }
b841314c 2858 }
592d7ade 2859
144040be
RG
2860 ++targetInfo.numberOfDistributedQueries;
2861
592d7ade
RG
2862 return true;
2863}
2864
144040be
RG
2865static unsigned int getWorkerLoad(size_t workerIdx)
2866{
2867 const auto mt = s_threadInfos[/* skip handler */ 1 + g_numDistributorThreads + workerIdx].mt;
2868 if (mt != nullptr) {
2869 return mt->numProcesses();
2870 }
2871 return 0;
2872}
2873
2874static unsigned int selectWorker(unsigned int hash)
2875{
2876 if (s_balancingFactor == 0) {
2877 return /* skip handler */ 1 + g_numDistributorThreads + (hash % g_numWorkerThreads);
2878 }
2879
2880 /* we start with one, representing the query we are currently handling */
2881 double currentLoad = 1;
2882 std::vector<unsigned int> load(g_numWorkerThreads);
2883 for (size_t idx = 0; idx < g_numWorkerThreads; idx++) {
2884 load[idx] = getWorkerLoad(idx);
2885 currentLoad += load[idx];
2886 // cerr<<"load for worker "<<idx<<" is "<<load[idx]<<endl;
2887 }
2888
2889 double targetLoad = (currentLoad / g_numWorkerThreads) * s_balancingFactor;
2890 // cerr<<"total load is "<<currentLoad<<", number of workers is "<<g_numWorkerThreads<<", target load is "<<targetLoad<<endl;
2891
2892 unsigned int worker = hash % g_numWorkerThreads;
1b9d2d46 2893 /* at least one server has to be at or below the average load */
596bf482
RG
2894 if (load[worker] > targetLoad) {
2895 ++g_stats.rebalancedQueries;
2896 do {
2897 // cerr<<"worker "<<worker<<" is above the target load, selecting another one"<<endl;
2898 worker = (worker + 1) % g_numWorkerThreads;
2899 }
2900 while(load[worker] > targetLoad);
144040be
RG
2901 }
2902
2903 return /* skip handler */ 1 + g_numDistributorThreads + worker;
2904}
2905
592d7ade
RG
2906// This function is only called by the distributor threads, when pdns-distributes-queries is set
2907void distributeAsyncFunction(const string& packet, const pipefunc_t& func)
2908{
2909 if (!isDistributorThread()) {
2910 g_log<<Logger::Error<<"distributeAsyncFunction() has been called by a worker ("<<t_id<<")"<<endl;
2911 exit(1);
2912 }
2913
2914 unsigned int hash = hashQuestion(packet.c_str(), packet.length(), g_disthashseed);
144040be 2915 unsigned int target = selectWorker(hash);
592d7ade
RG
2916
2917 ThreadMSG* tmsg = new ThreadMSG();
2918 tmsg->func = func;
2919 tmsg->wantAnswer = false;
2920
2921 if (!trySendingQueryToWorker(target, tmsg)) {
2922 /* if this function failed but did not raise an exception, it means that the pipe
2923 was full, let's try another one */
2924 unsigned int newTarget = 0;
2925 do {
2926 newTarget = /* skip handler */ 1 + g_numDistributorThreads + dns_random(g_numWorkerThreads);
2927 } while (newTarget == target);
2928
2929 if (!trySendingQueryToWorker(newTarget, tmsg)) {
2930 g_stats.queryPipeFullDrops++;
2931 delete tmsg;
2932 }
2933 }
00c9b8c1 2934}
3427fa8a 2935
d187038c 2936static void handlePipeRequest(int fd, FDMultiplexer::funcparam_t& var)
49a699c4 2937{
f26bf547 2938 ThreadMSG* tmsg = nullptr;
3ddb9247 2939
cf8cda18 2940 if(read(fd, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { // fd == readToThread || fd == readQueriesToThread
49a699c4
BH
2941 unixDie("read from thread pipe returned wrong size or error");
2942 }
3ddb9247 2943
2f22827a 2944 void *resp=0;
2945 try {
2946 resp = tmsg->func();
2947 }
2948 catch(std::exception& e) {
6d2010a8 2949 if(g_logCommonErrors)
e6a9dde5 2950 g_log<<Logger::Error<<"PIPE function we executed created exception: "<<e.what()<<endl; // but what if they wanted an answer.. we send 0
2f22827a 2951 }
2952 catch(PDNSException& e) {
6d2010a8 2953 if(g_logCommonErrors)
e6a9dde5 2954 g_log<<Logger::Error<<"PIPE function we executed created PDNS exception: "<<e.reason<<endl; // but what if they wanted an answer.. we send 0
2f22827a 2955 }
d7c676a5 2956 if(tmsg->wantAnswer) {
b243ca3b
RG
2957 const auto& threadInfo = s_threadInfos.at(t_id);
2958 if(write(threadInfo.pipes.writeFromThread, &resp, sizeof(resp)) != sizeof(resp)) {
d7c676a5 2959 delete tmsg;
00c9b8c1 2960 unixDie("write to thread pipe returned wrong size or error");
d7c676a5
RG
2961 }
2962 }
3ddb9247 2963
00c9b8c1 2964 delete tmsg;
49a699c4 2965}
09e6702a 2966
13034931
BH
2967template<class T> void *voider(const boost::function<T*()>& func)
2968{
2969 return func();
2970}
2971
b3b5459d
BH
2972vector<ComboAddress>& operator+=(vector<ComboAddress>&a, const vector<ComboAddress>& b)
2973{
2974 a.insert(a.end(), b.begin(), b.end());
2975 return a;
2976}
2977
92011b8f 2978vector<pair<string, uint16_t> >& operator+=(vector<pair<string, uint16_t> >&a, const vector<pair<string, uint16_t> >& b)
2979{
2980 a.insert(a.end(), b.begin(), b.end());
2981 return a;
2982}
2983
3ddb9247
PD
2984vector<pair<DNSName, uint16_t> >& operator+=(vector<pair<DNSName, uint16_t> >&a, const vector<pair<DNSName, uint16_t> >& b)
2985{
2986 a.insert(a.end(), b.begin(), b.end());
2987 return a;
2988}
2989
92011b8f 2990
387b9ca6
RG
2991/*
2992 This function should only be called by the handler to gather metrics, wipe the cache,
788eeb4c
RG
2993 reload the Lua script (not the Lua config) or change the current trace regex,
2994 and by the SNMP thread to gather metrics. */
b4e76a18 2995template<class T> T broadcastAccFunction(const boost::function<T*()>& func)
3427fa8a 2996{
b243ca3b 2997 if (!isHandlerThread()) {
788eeb4c 2998 g_log<<Logger::Error<<"broadcastAccFunction has been called by a worker ("<<t_id<<")"<<endl;
d77abca1 2999 exit(1);
d77abca1
RG
3000 }
3001
b243ca3b 3002 unsigned int n = 0;
3427fa8a 3003 T ret=T();
b243ca3b
RG
3004 for (const auto& threadInfo : s_threadInfos) {
3005 if (n++ == t_id) {
3006 continue;
3007 }
3008
3009 const auto& tps = threadInfo.pipes;
00c9b8c1
BH
3010 ThreadMSG* tmsg = new ThreadMSG();
3011 tmsg->func = boost::bind(voider<T>, func);
3012 tmsg->wantAnswer = true;
3ddb9247 3013
b841314c
RG
3014 if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) {
3015 delete tmsg;
3427fa8a 3016 unixDie("write to thread pipe returned wrong size or error");
b841314c 3017 }
3ddb9247 3018
49467864 3019 T* resp = nullptr;
3427fa8a
BH
3020 if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp))
3021 unixDie("read from thread pipe returned wrong size or error");
3ddb9247 3022
3427fa8a 3023 if(resp) {
3427fa8a
BH
3024 ret += *resp;
3025 delete resp;
49467864 3026 resp = nullptr;
3427fa8a
BH
3027 }
3028 }
3029 return ret;
3030}
3031
b4e76a18
RG
3032template string broadcastAccFunction(const boost::function<string*()>& fun); // explicit instantiation
3033template uint64_t broadcastAccFunction(const boost::function<uint64_t*()>& fun); // explicit instantiation
3034template vector<ComboAddress> broadcastAccFunction(const boost::function<vector<ComboAddress> *()>& fun); // explicit instantiation
3035template vector<pair<DNSName,uint16_t> > broadcastAccFunction(const boost::function<vector<pair<DNSName, uint16_t> > *()>& fun); // explicit instantiation
5ac6d761 3036template ThreadTimes broadcastAccFunction(const boost::function<ThreadTimes*()>& fun);
3427fa8a 3037
d187038c 3038static void handleRCC(int fd, FDMultiplexer::funcparam_t& var)
09e6702a 3039{
fbfc1809
RG
3040 try {
3041 string remote;
3042 string msg=s_rcc.recv(&remote);
3043 RecursorControlParser rcp;
3044 RecursorControlParser::func_t* command;
3ddb9247 3045
fbfc1809 3046 string answer=rcp.getAnswer(msg, &command);
f0f3f0b0 3047
fbfc1809
RG
3048 // If we are inside a chroot, we need to strip
3049 if (!arg()["chroot"].empty()) {
3050 size_t len = arg()["chroot"].length();
3051 remote = remote.substr(len);
3052 }
f0f3f0b0 3053
ab5c053d
BH
3054 s_rcc.send(answer, &remote);
3055 command();
3056 }
fbfc1809 3057 catch(const std::exception& e) {
e6a9dde5 3058 g_log<<Logger::Error<<"Error dealing with control socket request: "<<e.what()<<endl;
ab5c053d 3059 }
fbfc1809 3060 catch(const PDNSException& ae) {
e6a9dde5 3061 g_log<<Logger::Error<<"Error dealing with control socket request: "<<ae.reason<<endl;
ab5c053d 3062 }
09e6702a
BH
3063}
3064
d187038c 3065static void handleTCPClientReadable(int fd, FDMultiplexer::funcparam_t& var)
09e6702a 3066{
0b18b22e 3067 PacketID* pident=any_cast<PacketID>(&var);
667f7e60 3068 // cerr<<"handleTCPClientReadable called for fd "<<fd<<", pident->inNeeded: "<<pident->inNeeded<<", "<<pident->sock->getHandle()<<endl;
09e6702a 3069
667f7e60 3070 shared_array<char> buffer(new char[pident->inNeeded]);
09e6702a 3071
a683e8bd 3072 ssize_t ret=recv(fd, buffer.get(), pident->inNeeded,0);
09e6702a 3073 if(ret > 0) {
667f7e60 3074 pident->inMSG.append(&buffer[0], &buffer[ret]);
a683e8bd 3075 pident->inNeeded-=(size_t)ret;
825fa717 3076 if(!pident->inNeeded || pident->inIncompleteOkay) {
667f7e60
BH
3077 // cerr<<"Got entire load of "<<pident->inMSG.size()<<" bytes"<<endl;
3078 PacketID pid=*pident;
3079 string msg=pident->inMSG;
3ddb9247 3080
bb4bdbaf 3081 t_fdm->removeReadFD(fd);
3ddb9247 3082 MT->sendEvent(pid, &msg);
09e6702a
BH
3083 }
3084 else {
667f7e60 3085 // cerr<<"Still have "<<pident->inNeeded<<" left to go"<<endl;
09e6702a
BH
3086 }
3087 }
3088 else {
667f7e60 3089 PacketID tmp=*pident;
bb4bdbaf 3090 t_fdm->removeReadFD(fd); // pident might now be invalid (it isn't, but still)
09e6702a
BH
3091 string empty;
3092 MT->sendEvent(tmp, &empty); // this conveys error status
3093 }
3094}
3095
d187038c 3096static void handleTCPClientWritable(int fd, FDMultiplexer::funcparam_t& var)
09e6702a 3097{
0b18b22e 3098 PacketID* pid=any_cast<PacketID>(&var);
a683e8bd 3099 ssize_t ret=send(fd, pid->outMSG.c_str() + pid->outPos, pid->outMSG.size() - pid->outPos,0);
09e6702a 3100 if(ret > 0) {
a683e8bd 3101 pid->outPos+=(ssize_t)ret;
667f7e60
BH
3102 if(pid->outPos==pid->outMSG.size()) {
3103 PacketID tmp=*pid;
bb4bdbaf 3104 t_fdm->removeWriteFD(fd);
09e6702a
BH
3105 MT->sendEvent(tmp, &tmp.outMSG); // send back what we sent to convey everything is ok
3106 }
3107 }
3108 else { // error or EOF
667f7e60 3109 PacketID tmp(*pid);
bb4bdbaf 3110 t_fdm->removeWriteFD(fd);
09e6702a 3111 string sent;
998a4334 3112 MT->sendEvent(tmp, &sent); // we convey error status by sending empty string
09e6702a
BH
3113 }
3114}
3115
34801ab1 3116// resend event to everybody chained onto it
d187038c 3117static void doResends(MT_t::waiters_t::iterator& iter, PacketID resend, const string& content)
34801ab1
BH
3118{
3119 if(iter->key.chain.empty())
3120 return;
e27e91a8 3121 // cerr<<"doResends called!\n";
34801ab1
BH
3122 for(PacketID::chain_t::iterator i=iter->key.chain.begin(); i != iter->key.chain.end() ; ++i) {
3123 resend.fd=-1;
3124 resend.id=*i;
e27e91a8 3125 // cerr<<"\tResending "<<content.size()<<" bytes for fd="<<resend.fd<<" and id="<<resend.id<<endl;
4665c31e 3126
34801ab1
BH
3127 MT->sendEvent(resend, &content);
3128 g_stats.chainResends++;
34801ab1
BH
3129 }
3130}
3131
d187038c 3132static void handleUDPServerResponse(int fd, FDMultiplexer::funcparam_t& var)
09e6702a 3133{
600fc20b 3134 PacketID pid=any_cast<PacketID>(var);
a683e8bd 3135 ssize_t len;
fae8fe07
RG
3136 std::string packet;
3137 packet.resize(g_outgoingEDNSBufsize);
996c89cc 3138 ComboAddress fromaddr;
09e6702a
BH
3139 socklen_t addrlen=sizeof(fromaddr);
3140
fae8fe07 3141 len=recvfrom(fd, &packet.at(0), packet.size(), 0, (sockaddr *)&fromaddr, &addrlen);
c1da7976 3142
a683e8bd 3143 if(len < (ssize_t) sizeof(dnsheader)) {
998a4334 3144 if(len < 0)
996c89cc 3145 ; // cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
09e6702a 3146 else {
3ddb9247 3147 g_stats.serverParseError++;
09e6702a 3148 if(g_logCommonErrors)
e6a9dde5 3149 g_log<<Logger::Error<<"Unable to parse packet from remote UDP server "<< fromaddr.toString() <<
e44d9fa7 3150 ": packet smaller than DNS header"<<endl;
998a4334 3151 }
34801ab1 3152
49a699c4 3153 t_udpclientsocks->returnSocket(fd);
34801ab1
BH
3154 string empty;
3155
3156 MT_t::waiters_t::iterator iter=MT->d_waiters.find(pid);
3ddb9247 3157 if(iter != MT->d_waiters.end())
34801ab1 3158 doResends(iter, pid, empty);
3ddb9247 3159
34801ab1 3160 MT->sendEvent(pid, &empty); // this denotes error (does lookup again.. at least L1 will be hot)
998a4334 3161 return;
3ddb9247 3162 }
998a4334 3163
fae8fe07 3164 packet.resize(len);
998a4334 3165 dnsheader dh;
fae8fe07 3166 memcpy(&dh, &packet.at(0), sizeof(dh));
3ddb9247 3167
6da3b3ad
PD
3168 PacketID pident;
3169 pident.remote=fromaddr;
3170 pident.id=dh.id;
3171 pident.fd=fd;
34801ab1 3172
33a928af 3173 if(!dh.qr && g_logCommonErrors) {
e6a9dde5 3174 g_log<<Logger::Notice<<"Not taking data from question on outgoing socket from "<< fromaddr.toStringWithPort() <<endl;
6da3b3ad
PD
3175 }
3176
3177 if(!dh.qdcount || // UPC, Nominum, very old BIND on FormErr, NSD
3178 !dh.qr) { // one weird server
3179 pident.domain.clear();
3180 pident.type = 0;
3181 }
3182 else {
3183 try {
0b31e67e 3184 if(len > 12)
fae8fe07 3185 pident.domain=DNSName(&packet.at(0), len, 12, false, &pident.type); // don't copy this from above - we need to do the actual read
6da3b3ad
PD
3186 }
3187 catch(std::exception& e) {
3188 g_stats.serverParseError++; // won't be fed to lwres.cc, so we have to increment
e6a9dde5 3189 g_log<<Logger::Warning<<"Error in packet from remote nameserver "<< fromaddr.toStringWithPort() << ": "<<e.what() << endl;
6da3b3ad 3190 return;
34801ab1 3191 }
6da3b3ad 3192 }
34801ab1 3193
6da3b3ad
PD
3194 MT_t::waiters_t::iterator iter=MT->d_waiters.find(pident);
3195 if(iter != MT->d_waiters.end()) {
3196 doResends(iter, pident, packet);
3197 }
c1da7976 3198
6da3b3ad 3199retryWithName:
4957a608 3200
6da3b3ad
PD
3201 if(!MT->sendEvent(pident, &packet)) {
3202 // 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
3203 for(MT_t::waiters_t::iterator mthread=MT->d_waiters.begin(); mthread!=MT->d_waiters.end(); ++mthread) {
3204 if(pident.fd==mthread->key.fd && mthread->key.remote==pident.remote && mthread->key.type == pident.type &&
e325f20c 3205 pident.domain == mthread->key.domain) {
6da3b3ad 3206 mthread->key.nearMisses++;
998a4334 3207 }
6da3b3ad
PD
3208
3209 // be a bit paranoid here since we're weakening our matching
3ddb9247 3210 if(pident.domain.empty() && !mthread->key.domain.empty() && !pident.type && mthread->key.type &&
6da3b3ad
PD
3211 pident.id == mthread->key.id && mthread->key.remote == pident.remote) {
3212 // cerr<<"Empty response, rest matches though, sending to a waiter"<<endl;
3213 pident.domain = mthread->key.domain;
3214 pident.type = mthread->key.type;
3215 goto retryWithName; // note that this only passes on an error, lwres will still reject the packet
d4fb76e9 3216 }
09e6702a 3217 }
6da3b3ad
PD
3218 g_stats.unexpectedCount++; // if we made it here, it really is an unexpected answer
3219 if(g_logCommonErrors) {
e6a9dde5 3220 g_log<<Logger::Warning<<"Discarding unexpected packet from "<<fromaddr.toStringWithPort()<<": "<< (pident.domain.empty() ? "<empty>" : pident.domain.toString())<<", "<<pident.type<<", "<<MT->d_waiters.size()<<" waiters"<<endl;
d8f6d49f 3221 }
09e6702a 3222 }
6da3b3ad
PD
3223 else if(fd >= 0) {
3224 t_udpclientsocks->returnSocket(fd);
3225 }
09e6702a
BH
3226}
3227
1f4abb20
BH
3228FDMultiplexer* getMultiplexer()
3229{
3230 FDMultiplexer* ret;
f26bf547 3231 for(const auto& i : FDMultiplexer::getMultiplexerMap()) {
1f4abb20 3232 try {
f26bf547 3233 ret=i.second();
1f4abb20
BH
3234 return ret;
3235 }
98d0ee4a 3236 catch(FDMultiplexerException &fe) {
e6a9dde5 3237 g_log<<Logger::Error<<"Non-fatal error initializing possible multiplexer ("<<fe.what()<<"), falling back"<<endl;
98d0ee4a
BH
3238 }
3239 catch(...) {
e6a9dde5 3240 g_log<<Logger::Error<<"Non-fatal error initializing possible multiplexer"<<endl;
98d0ee4a 3241 }
1f4abb20 3242 }
e6a9dde5 3243 g_log<<Logger::Error<<"No working multiplexer found!"<<endl;
1f4abb20
BH
3244 exit(1);
3245}
3246
3ddb9247 3247
d187038c 3248static string* doReloadLuaScript()
4485aa35 3249{
674cf0f6 3250 string fname= ::arg()["lua-dns-script"];
4485aa35 3251 try {
674cf0f6 3252 if(fname.empty()) {
f26bf547 3253 t_pdl.reset();
377602e3 3254 g_log<<Logger::Info<<t_id<<" Unloaded current lua script"<<endl;
0f39c1a3 3255 return new string("unloaded\n");
4485aa35
BH
3256 }
3257 else {
9694e14f
AT
3258 t_pdl = std::make_shared<RecursorLua4>();
3259 t_pdl->loadFile(fname);
4485aa35
BH
3260 }
3261 }
fdbf35ac 3262 catch(std::exception& e) {
e6a9dde5 3263 g_log<<Logger::Error<<t_id<<" Retaining current script, error from '"<<fname<<"': "<< e.what() <<endl;
0f39c1a3 3264 return new string("retaining current script, error from '"+fname+"': "+e.what()+"\n");
4485aa35 3265 }
3ddb9247 3266
e6a9dde5 3267 g_log<<Logger::Warning<<t_id<<" (Re)loaded lua script from '"<<fname<<"'"<<endl;
0f39c1a3 3268 return new string("(re)loaded '"+fname+"'\n");
4485aa35
BH
3269}
3270
49a699c4
BH
3271string doQueueReloadLuaScript(vector<string>::const_iterator begin, vector<string>::const_iterator end)
3272{
3ddb9247 3273 if(begin != end)
49a699c4 3274 ::arg().set("lua-dns-script") = *begin;
3ddb9247 3275
0f39c1a3 3276 return broadcastAccFunction<string>(doReloadLuaScript);
3ddb9247 3277}
49a699c4 3278
d187038c 3279static string* pleaseUseNewTraceRegex(const std::string& newRegex)
77499b05
BH
3280try
3281{
3282 if(newRegex.empty()) {
f26bf547 3283 t_traceRegex.reset();
77499b05
BH
3284 return new string("unset\n");
3285 }
3286 else {
f26bf547 3287 t_traceRegex = std::make_shared<Regex>(newRegex);
77499b05
BH
3288 return new string("ok\n");
3289 }
3290}
3f81d239 3291catch(PDNSException& ae)
77499b05
BH
3292{
3293 return new string(ae.reason+"\n");
3294}
3295
3296string doTraceRegex(vector<string>::const_iterator begin, vector<string>::const_iterator end)
3297{
3298 return broadcastAccFunction<string>(boost::bind(pleaseUseNewTraceRegex, begin!=end ? *begin : ""));
3299}
3300
4e9a20e6 3301static void checkLinuxIPv6Limits()
3302{
3303#ifdef __linux__
3304 string line;
3305 if(readFileIfThere("/proc/sys/net/ipv6/route/max_size", &line)) {
335da0ba 3306 int lim=std::stoi(line);
4e9a20e6 3307 if(lim < 16384) {
e6a9dde5 3308 g_log<<Logger::Error<<"If using IPv6, please raise sysctl net.ipv6.route.max_size, currently set to "<<lim<<" which is < 16384"<<endl;
4e9a20e6 3309 }
3310 }
3311#endif
3312}
36849ff2 3313static void checkOrFixFDS()
4e9a20e6 3314{
c0063e60 3315 unsigned int availFDs=getFilenumLimit();
3316 unsigned int wantFDs = g_maxMThreads * g_numWorkerThreads +25; // even healthier margin then before
3317
3318 if(wantFDs > availFDs) {
067ad20e 3319 unsigned int hardlimit= getFilenumLimit(true);
3320 if(hardlimit >= wantFDs) {
c0063e60 3321 setFilenumLimit(wantFDs);
e6a9dde5 3322 g_log<<Logger::Warning<<"Raised soft limit on number of filedescriptors to "<<wantFDs<<" to match max-mthreads and threads settings"<<endl;
36849ff2 3323 }
3324 else {
067ad20e 3325 int newval = (hardlimit - 25) / g_numWorkerThreads;
e6a9dde5 3326 g_log<<Logger::Warning<<"Insufficient number of filedescriptors available for max-mthreads*threads setting! ("<<hardlimit<<" < "<<wantFDs<<"), reducing max-mthreads to "<<newval<<endl;
36849ff2 3327 g_maxMThreads = newval;
067ad20e 3328 setFilenumLimit(hardlimit);
36849ff2 3329 }
3330 }
4e9a20e6 3331}
77499b05 3332
c390b2da 3333static void* recursorThread(unsigned int tid, const string& threadName);
51e2144e 3334
f26bf547 3335static void* pleaseSupplantACLs(std::shared_ptr<NetmaskGroup> ng)
49a699c4
BH
3336{
3337 t_allowFrom = ng;
f26bf547 3338 return nullptr;
49a699c4
BH
3339}
3340
dbd23fc2
BH
3341int g_argc;
3342char** g_argv;
3343
18af64a8 3344void parseACLs()
f7c1d4e3 3345{
18af64a8 3346 static bool l_initialized;
3ddb9247 3347
49a699c4 3348 if(l_initialized) { // only reload configuration file on second call
18af64a8 3349 string configname=::arg()["config-dir"]+"/recursor.conf";
3e63da83
JR
3350 if(::arg()["config-name"]!="") {
3351 configname=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf";
3352 }
18af64a8 3353 cleanSlashes(configname);
3ddb9247
PD
3354
3355 if(!::arg().preParseFile(configname.c_str(), "allow-from-file"))
7e818521 3356 throw runtime_error("Unable to re-parse configuration file '"+configname+"'");
49a699c4 3357 ::arg().preParseFile(configname.c_str(), "allow-from", LOCAL_NETS);
242b90e1 3358 ::arg().preParseFile(configname.c_str(), "include-dir");
829849d6
AT
3359 ::arg().preParse(g_argc, g_argv, "include-dir");
3360
3361 // then process includes
3362 std::vector<std::string> extraConfigs;
242b90e1
AT
3363 ::arg().gatherIncludes(extraConfigs);
3364
1dc8f4d0 3365 for(const std::string& fn : extraConfigs) {
7e818521 3366 if(!::arg().preParseFile(fn.c_str(), "allow-from-file", ::arg()["allow-from-file"]))
3367 throw runtime_error("Unable to re-parse configuration file include '"+fn+"'");
3368 if(!::arg().preParseFile(fn.c_str(), "allow-from", ::arg()["allow-from"]))
3369 throw runtime_error("Unable to re-parse configuration file include '"+fn+"'");
829849d6 3370 }
ca2c884c
AT
3371
3372 ::arg().preParse(g_argc, g_argv, "allow-from-file");
3373 ::arg().preParse(g_argc, g_argv, "allow-from");
f27e6356 3374 }
49a699c4 3375
f26bf547
RG
3376 std::shared_ptr<NetmaskGroup> oldAllowFrom = t_allowFrom;
3377 std::shared_ptr<NetmaskGroup> allowFrom = std::make_shared<NetmaskGroup>();
3ddb9247 3378
2c95fc65
BH
3379 if(!::arg()["allow-from-file"].empty()) {
3380 string line;
2c95fc65
BH
3381 ifstream ifs(::arg()["allow-from-file"].c_str());
3382 if(!ifs) {
9c61b9d0 3383 throw runtime_error("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror());
2c95fc65
BH
3384 }
3385
3386 string::size_type pos;
3387 while(getline(ifs,line)) {
3388 pos=line.find('#');
3389 if(pos!=string::npos)
3390 line.resize(pos);
3391 trim(line);
3392 if(line.empty())
3393 continue;
3394
18af64a8 3395 allowFrom->addMask(line);
2c95fc65 3396 }
e6a9dde5 3397 g_log<<Logger::Warning<<"Done parsing " << allowFrom->size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"<<endl;
2c95fc65
BH
3398 }
3399 else if(!::arg()["allow-from"].empty()) {
f7c1d4e3
BH
3400 vector<string> ips;
3401 stringtok(ips, ::arg()["allow-from"], ", ");
3ddb9247 3402
e6a9dde5 3403 g_log<<Logger::Warning<<"Only allowing queries from: ";
f7c1d4e3 3404 for(vector<string>::const_iterator i = ips.begin(); i!= ips.end(); ++i) {
18af64a8 3405 allowFrom->addMask(*i);
f7c1d4e3 3406 if(i!=ips.begin())
e6a9dde5
PL
3407 g_log<<Logger::Warning<<", ";
3408 g_log<<Logger::Warning<<*i;
f7c1d4e3 3409 }
e6a9dde5 3410 g_log<<Logger::Warning<<endl;
f7c1d4e3 3411 }
49a699c4 3412 else {
3ddb9247 3413 if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
377602e3 3414 g_log<<Logger::Warning<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl;
f26bf547 3415 allowFrom = nullptr;
49a699c4 3416 }
3ddb9247 3417
49a699c4 3418 g_initialAllowFrom = allowFrom;
d7dae798 3419 broadcastFunction(boost::bind(pleaseSupplantACLs, allowFrom));
f26bf547 3420 oldAllowFrom = nullptr;
3ddb9247 3421
49a699c4 3422 l_initialized = true;
18af64a8
BH
3423}
3424
795215f2 3425
756e82cf 3426static void setupDelegationOnly()
3427{
3428 vector<string> parts;
3429 stringtok(parts, ::arg()["delegation-only"], ", \t");
3430 for(const auto& p : parts) {
9065eb05 3431 SyncRes::addDelegationOnly(DNSName(p));
756e82cf 3432 }
3433}
795215f2 3434
8fd25133
RG
3435static std::map<unsigned int, std::set<int> > parseCPUMap()
3436{
3437 std::map<unsigned int, std::set<int> > result;
3438
3439 const std::string value = ::arg()["cpu-map"];
3440
3441 if (!value.empty() && !isSettingThreadCPUAffinitySupported()) {
e6a9dde5 3442 g_log<<Logger::Warning<<"CPU mapping requested but not supported, skipping"<<endl;
8fd25133
RG
3443 return result;
3444 }
3445
3446 std::vector<std::string> parts;
3447
3448 stringtok(parts, value, " \t");
3449
3450 for(const auto& part : parts) {
3451 if (part.find('=') == string::npos)
3452 continue;
3453
3454 try {
3455 auto headers = splitField(part, '=');
3456 trim(headers.first);
3457 trim(headers.second);
3458
3459 unsigned int threadId = pdns_stou(headers.first);
3460 std::vector<std::string> cpus;
3461
3462 stringtok(cpus, headers.second, ",");
3463
3464 for(const auto& cpu : cpus) {
3465 int cpuId = std::stoi(cpu);
3466
3467 result[threadId].insert(cpuId);
3468 }
3469 }
3470 catch(const std::exception& e) {
e6a9dde5 3471 g_log<<Logger::Error<<"Error parsing cpu-map entry '"<<part<<"': "<<e.what()<<endl;
8fd25133
RG
3472 }
3473 }
3474
3475 return result;
3476}
3477
3478static void setCPUMap(const std::map<unsigned int, std::set<int> >& cpusMap, unsigned int n, pthread_t tid)
3479{
3480 const auto& cpuMapping = cpusMap.find(n);
3481 if (cpuMapping != cpusMap.cend()) {
3482 int rc = mapThreadToCPUList(tid, cpuMapping->second);
3483 if (rc == 0) {
e6a9dde5 3484 g_log<<Logger::Info<<"CPU affinity for worker "<<n<<" has been set to CPU map:";
8fd25133 3485 for (const auto cpu : cpuMapping->second) {
e6a9dde5 3486 g_log<<Logger::Info<<" "<<cpu;
8fd25133 3487 }
e6a9dde5 3488 g_log<<Logger::Info<<endl;
8fd25133
RG
3489 }
3490 else {
e6a9dde5 3491 g_log<<Logger::Warning<<"Error setting CPU affinity for worker "<<n<<" to CPU map:";
8fd25133 3492 for (const auto cpu : cpuMapping->second) {
e6a9dde5 3493 g_log<<Logger::Info<<" "<<cpu;
8fd25133 3494 }
e6a9dde5 3495 g_log<<Logger::Info<<strerror(rc)<<endl;
8fd25133
RG
3496 }
3497 }
3498}
3499
af1377b7
NC
3500#ifdef NOD_ENABLED
3501static void setupNODThread()
3502{
3503 if (g_nodEnabled) {
b78727c6
NC
3504 uint32_t num_cells = ::arg().asNum("new-domain-db-size");
3505 t_nodDBp = std::make_shared<nod::NODDB>(num_cells);
af1377b7
NC
3506 try {
3507 t_nodDBp->setCacheDir(::arg()["new-domain-history-dir"]);
3508 }
3509 catch (const PDNSException& e) {
3510 g_log<<Logger::Error<<"new-domain-history-dir (" << ::arg()["new-domain-history-dir"] << ") is not readable or does not exist"<<endl;
3511 _exit(1);
3512 }
3513 if (!t_nodDBp->init()) {
3514 g_log<<Logger::Error<<"Could not initialize domain tracking"<<endl;
3515 _exit(1);
3516 }
41c542ec 3517 std::thread t(nod::NODDB::startHousekeepingThread, t_nodDBp, std::this_thread::get_id());
af1377b7 3518 t.detach();
ca2526f5 3519 g_nod_pbtag = ::arg()["new-domain-pb-tag"];
41c542ec
NC
3520 }
3521 if (g_udrEnabled) {
b78727c6
NC
3522 uint32_t num_cells = ::arg().asNum("unique-response-db-size");
3523 t_udrDBp = std::make_shared<nod::UniqueResponseDB>(num_cells);
41c542ec
NC
3524 try {
3525 t_udrDBp->setCacheDir(::arg()["unique-response-history-dir"]);
3526 }
3527 catch (const PDNSException& e) {
3528 g_log<<Logger::Error<<"unique-response-history-dir (" << ::arg()["unique-response-history-dir"] << ") is not readable or does not exist"<<endl;
3529 _exit(1);
3530 }
3531 if (!t_udrDBp->init()) {
3532 g_log<<Logger::Error<<"Could not initialize unique response tracking"<<endl;
3533 _exit(1);
3534 }
3535 std::thread t(nod::UniqueResponseDB::startHousekeepingThread, t_udrDBp, std::this_thread::get_id());
af1377b7 3536 t.detach();
ca2526f5 3537 g_udr_pbtag = ::arg()["unique-response-pb-tag"];
af1377b7
NC
3538 }
3539}
3540
3541void parseNODWhitelist(const std::string& wlist)
3542{
3543 vector<string> parts;
3544 stringtok(parts, wlist, ",; ");
3545 for(const auto& a : parts) {
3546 g_nodDomainWL.add(DNSName(a));
3547 }
3548}
3549
3550static void setupNODGlobal()
3551{
3552 // Setup NOD subsystem
3553 g_nodEnabled = ::arg().mustDo("new-domain-tracking");
3554 g_nodLookupDomain = DNSName(::arg()["new-domain-lookup"]);
3555 g_nodLog = ::arg().mustDo("new-domain-log");
3556 parseNODWhitelist(::arg()["new-domain-whitelist"]);
41c542ec
NC
3557
3558 // Setup Unique DNS Response subsystem
3559 g_udrEnabled = ::arg().mustDo("unique-response-tracking");
3560 g_udrLog = ::arg().mustDo("unique-response-log");
af1377b7
NC
3561}
3562#endif /* NOD_ENABLED */
3563
d187038c 3564static int serviceMain(int argc, char*argv[])
18af64a8 3565{
e6a9dde5
PL
3566 g_log.setName(s_programname);
3567 g_log.disableSyslog(::arg().mustDo("disable-syslog"));
3568 g_log.setTimestamps(::arg().mustDo("log-timestamp"));
18af64a8
BH
3569
3570 if(!::arg()["logging-facility"].empty()) {
f8499e52
BH
3571 int val=logFacilityToLOG(::arg().asNum("logging-facility") );
3572 if(val >= 0)
e6a9dde5 3573 g_log.setFacility(val);
18af64a8 3574 else
e6a9dde5 3575 g_log<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl;
18af64a8
BH
3576 }
3577
ba1a571d 3578 showProductVersion();
3afde9b2 3579
06ea9015 3580 g_disthashseed=dns_random(0xffffffff);
3581
b7ef5828
PL
3582 checkLinuxIPv6Limits();
3583 try {
3584 vector<string> addrs;
3585 if(!::arg()["query-local-address6"].empty()) {
3586 SyncRes::s_doIPv6=true;
e6a9dde5 3587 g_log<<Logger::Warning<<"Enabling IPv6 transport for outgoing queries"<<endl;
b7ef5828
PL
3588
3589 stringtok(addrs, ::arg()["query-local-address6"], ", ;");
3590 for(const string& addr : addrs) {
3591 g_localQueryAddresses6.push_back(ComboAddress(addr));
3592 }
3593 }
3594 else {
e6a9dde5 3595 g_log<<Logger::Warning<<"NOT using IPv6 for outgoing queries - set 'query-local-address6=::' to enable"<<endl;
b7ef5828
PL
3596 }
3597 addrs.clear();
3598 stringtok(addrs, ::arg()["query-local-address"], ", ;");
3599 for(const string& addr : addrs) {
3600 g_localQueryAddresses4.push_back(ComboAddress(addr));
3601 }
3602 }
3603 catch(std::exception& e) {
e6a9dde5 3604 g_log<<Logger::Error<<"Assigning local query addresses: "<<e.what();
b7ef5828
PL
3605 exit(99);
3606 }
3607
e48c6b8a
PL
3608 // keep this ABOVE loadRecursorLuaConfig!
3609 if(::arg()["dnssec"]=="off")
3610 g_dnssecmode=DNSSECMode::Off;
3611 else if(::arg()["dnssec"]=="process-no-validate")
3612 g_dnssecmode=DNSSECMode::ProcessNoValidate;
3613 else if(::arg()["dnssec"]=="process")
3614 g_dnssecmode=DNSSECMode::Process;
3615 else if(::arg()["dnssec"]=="validate")
3616 g_dnssecmode=DNSSECMode::ValidateAll;
3617 else if(::arg()["dnssec"]=="log-fail")
3618 g_dnssecmode=DNSSECMode::ValidateForLog;
3619 else {
e6a9dde5 3620 g_log<<Logger::Error<<"Unknown DNSSEC mode "<<::arg()["dnssec"]<<endl;
e48c6b8a
PL
3621 exit(1);
3622 }
3623
9a3ab3e4
KM
3624 g_signatureInceptionSkew = ::arg().asNum("signature-inception-skew");
3625 if (g_signatureInceptionSkew < 0) {
3626 g_log<<Logger::Error<<"A negative value for 'signature-inception-skew' is not allowed"<<endl;
3627 exit(1);
3628 }
3629
e48c6b8a 3630 g_dnssecLogBogus = ::arg().mustDo("dnssec-log-bogus");
d377bb54 3631 g_maxNSEC3Iterations = ::arg().asNum("nsec3-max-iterations");
e48c6b8a 3632
a6f7f5fe 3633 g_maxCacheEntries = ::arg().asNum("max-cache-entries");
3634 g_maxPacketCacheEntries = ::arg().asNum("max-packetcache-entries");
e6ec15bf
RG
3635
3636 luaConfigDelayedThreads delayedLuaThreads;
0f5785a6 3637 try {
e6ec15bf 3638 loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads);
0f5785a6
PL
3639 }
3640 catch (PDNSException &e) {
e6a9dde5 3641 g_log<<Logger::Error<<"Cannot load Lua configuration: "<<e.reason<<endl;
0f5785a6
PL
3642 exit(1);
3643 }
ad42489c 3644
18af64a8 3645 parseACLs();
d6f3fcfa 3646 initPublicSuffixList(::arg()["public-suffix-list-file"]);
92011b8f 3647
eb5bae86 3648 if(!::arg()["dont-query"].empty()) {
eb5bae86
BH
3649 vector<string> ips;
3650 stringtok(ips, ::arg()["dont-query"], ", ");
66e0b6ea
BH
3651 ips.push_back("0.0.0.0");
3652 ips.push_back("::");
c36bc97a 3653
e6a9dde5 3654 g_log<<Logger::Warning<<"Will not send queries to: ";
eb5bae86 3655 for(vector<string>::const_iterator i = ips.begin(); i!= ips.end(); ++i) {
9065eb05 3656 SyncRes::addDontQuery(*i);
eb5bae86 3657 if(i!=ips.begin())
e6a9dde5
PL
3658 g_log<<Logger::Warning<<", ";
3659 g_log<<Logger::Warning<<*i;
eb5bae86 3660 }
e6a9dde5 3661 g_log<<Logger::Warning<<endl;
eb5bae86
BH
3662 }
3663
f7c1d4e3 3664 g_quiet=::arg().mustDo("quiet");
3ddb9247 3665
b243ca3b 3666 /* this needs to be done before parseACLs(), which call broadcastFunction() */
1bc3c142
BH
3667 g_weDistributeQueries = ::arg().mustDo("pdns-distributes-queries");
3668 if(g_weDistributeQueries) {
b243ca3b 3669 g_log<<Logger::Warning<<"PowerDNS Recursor itself will distribute queries over threads"<<endl;
1bc3c142 3670 }
3ddb9247 3671
756e82cf 3672 setupDelegationOnly();
b33c2462 3673 g_outgoingEDNSBufsize=::arg().asNum("edns-outgoing-bufsize");
756e82cf 3674
77499b05
BH
3675 if(::arg()["trace"]=="fail") {
3676 SyncRes::setDefaultLogMode(SyncRes::Store);
3677 }
3678 else if(::arg().mustDo("trace")) {
3679 SyncRes::setDefaultLogMode(SyncRes::Log);
f7c1d4e3
BH
3680 ::arg().set("quiet")="no";
3681 g_quiet=false;
3e9c6c0a 3682 g_dnssecLOG=true;
f7c1d4e3 3683 }
43a9b290
PL
3684 string myHostname = getHostname();
3685 if (myHostname == "UNKNOWN"){
3686 g_log<<Logger::Warning<<"Unable to get the hostname, NSID and id.server values will be empty"<<endl;
3687 myHostname = "";
d0983bff 3688 }
3ddb9247 3689
aadceba8 3690 SyncRes::s_minimumTTL = ::arg().asNum("minimum-ttl-override");
5cf4b2e7 3691 SyncRes::s_minimumECSTTL = ::arg().asNum("ecs-minimum-ttl-override");
aadceba8 3692
1051f8a9
BH
3693 SyncRes::s_nopacketcache = ::arg().mustDo("disable-packetcache");
3694
f7c1d4e3 3695 SyncRes::s_maxnegttl=::arg().asNum("max-negative-ttl");
b9473937 3696 SyncRes::s_maxbogusttl=::arg().asNum("max-cache-bogus-ttl");
63637fd8 3697 SyncRes::s_maxcachettl=max(::arg().asNum("max-cache-ttl"), 15);
1051f8a9 3698 SyncRes::s_packetcachettl=::arg().asNum("packetcache-ttl");
79ec0627
PL
3699 // Cap the packetcache-servfail-ttl to the packetcache-ttl
3700 uint32_t packetCacheServFailTTL = ::arg().asNum("packetcache-servfail-ttl");
3701 SyncRes::s_packetcacheservfailttl=(packetCacheServFailTTL > SyncRes::s_packetcachettl) ? SyncRes::s_packetcachettl : packetCacheServFailTTL;
628e2c7b
PA
3702 SyncRes::s_serverdownmaxfails=::arg().asNum("server-down-max-fails");
3703 SyncRes::s_serverdownthrottletime=::arg().asNum("server-down-throttle-time");
f7c1d4e3 3704 SyncRes::s_serverID=::arg()["server-id"];
173d790e 3705 SyncRes::s_maxqperq=::arg().asNum("max-qperq");
9de3e034 3706 SyncRes::s_maxtotusec=1000*::arg().asNum("max-total-msec");
7c3398aa 3707 SyncRes::s_maxdepth=::arg().asNum("max-recursion-depth");
01402d56 3708 SyncRes::s_rootNXTrust = ::arg().mustDo( "root-nx-trust");
f7c1d4e3 3709 if(SyncRes::s_serverID.empty()) {
d0983bff 3710 SyncRes::s_serverID = myHostname;
f7c1d4e3 3711 }
3ddb9247 3712
e9f9b8ec
RG
3713 SyncRes::s_ecsipv4limit = ::arg().asNum("ecs-ipv4-bits");
3714 SyncRes::s_ecsipv6limit = ::arg().asNum("ecs-ipv6-bits");
c9783016 3715 SyncRes::clearECSStats();
fd8898fb 3716 SyncRes::s_ecsipv4cachelimit = ::arg().asNum("ecs-ipv4-cache-bits");
3717 SyncRes::s_ecsipv6cachelimit = ::arg().asNum("ecs-ipv6-cache-bits");
ed9019c9 3718 SyncRes::s_ecscachelimitttl = ::arg().asNum("ecs-cache-limit-ttl");
e9f9b8ec 3719
8a3a3822
RG
3720 if (!::arg().isEmpty("ecs-scope-zero-address")) {
3721 ComboAddress scopeZero(::arg()["ecs-scope-zero-address"]);
3722 SyncRes::setECSScopeZeroAddress(Netmask(scopeZero, scopeZero.isIPv4() ? 32 : 128));
3723 }
3724 else {
3725 bool found = false;
3726 for (const auto& addr : g_localQueryAddresses4) {
3727 if (!IsAnyAddress(addr)) {
3728 SyncRes::setECSScopeZeroAddress(Netmask(addr, 32));
3729 found = true;
3730 break;
3731 }
3732 }
3733 if (!found) {
3734 for (const auto& addr : g_localQueryAddresses6) {
3735 if (!IsAnyAddress(addr)) {
3736 SyncRes::setECSScopeZeroAddress(Netmask(addr, 128));
3737 found = true;
3738 break;
3739 }
3740 }
3741 if (!found) {
3742 SyncRes::setECSScopeZeroAddress(Netmask("127.0.0.1/32"));
3743 }
3744 }
3745 }
3746
2fe3354d
CH
3747 SyncRes::parseEDNSSubnetWhitelist(::arg()["edns-subnet-whitelist"]);
3748 SyncRes::parseEDNSSubnetAddFor(::arg()["ecs-add-for"]);
3749 g_useIncomingECS = ::arg().mustDo("use-incoming-edns-subnet");
3750
5cc8371b 3751 g_XPFAcl.toMasks(::arg()["xpf-allow-from"]);
59cb4a79 3752 g_xpfRRCode = ::arg().asNum("xpf-rr-code");
5cc8371b 3753
5b0ddd18 3754 g_networkTimeoutMsec = ::arg().asNum("network-timeout");
bb4bdbaf 3755
49a699c4 3756 g_initialDomainMap = parseAuthAndForwards();
3ddb9247 3757
08f3f638 3758 g_latencyStatSize=::arg().asNum("latency-statistic-size");
3ddb9247 3759
f7c1d4e3 3760 g_logCommonErrors=::arg().mustDo("log-common-errors");
98d36505 3761 g_logRPZChanges = ::arg().mustDo("log-rpz-changes");
e661a20b
PD
3762
3763 g_anyToTcp = ::arg().mustDo("any-to-tcp");
a09a8ce0
PD
3764 g_udpTruncationThreshold = ::arg().asNum("udp-truncation-threshold");
3765
b3adda56
PD
3766 g_lowercaseOutgoing = ::arg().mustDo("lowercase-outgoing");
3767
b243ca3b 3768 g_numDistributorThreads = ::arg().asNum("distributor-threads");
810ff705 3769 g_numWorkerThreads = ::arg().asNum("threads");
1c4f2e1b 3770 if (g_numWorkerThreads < 1) {
e6a9dde5 3771 g_log<<Logger::Warning<<"Asked to run with 0 threads, raising to 1 instead"<<endl;
1c4f2e1b
RG
3772 g_numWorkerThreads = 1;
3773 }
3774
b243ca3b 3775 g_numThreads = g_numDistributorThreads + g_numWorkerThreads;
810ff705
RG
3776 g_maxMThreads = ::arg().asNum("max-mthreads");
3777
00b8cadc
RG
3778 g_gettagNeedsEDNSOptions = ::arg().mustDo("gettag-needs-edns-options");
3779
0ec489bf 3780 g_statisticsInterval = ::arg().asNum("statistics-interval");
3781
144040be 3782 s_balancingFactor = ::arg().asDouble("distribution-load-factor");
078be17f
RG
3783 if (s_balancingFactor != 0.0 && s_balancingFactor < 1.0) {
3784 s_balancingFactor = 0.0;
3785 g_log<<Logger::Warning<<"Asked to run with a distribution-load-factor below 1.0, disabling it instead"<<endl;
3786 }
144040be 3787
810ff705
RG
3788#ifdef SO_REUSEPORT
3789 g_reusePort = ::arg().mustDo("reuseport");
3790#endif
3791
b243ca3b 3792 s_threadInfos.resize(g_numDistributorThreads + g_numWorkerThreads + /* handler */ 1);
810ff705 3793
b243ca3b
RG
3794 if (g_reusePort) {
3795 if (g_weDistributeQueries) {
3796 /* first thread is the handler, then distributors */
3797 for (unsigned int threadId = 1; threadId <= g_numDistributorThreads; threadId++) {
3798 auto& deferredAdds = s_threadInfos.at(threadId).deferredAdds;
adb6cd72 3799 auto& tcpSockets = s_threadInfos.at(threadId).tcpSockets;
b243ca3b 3800 makeUDPServerSockets(deferredAdds);
adb6cd72 3801 makeTCPServerSockets(deferredAdds, tcpSockets);
b243ca3b
RG
3802 }
3803 }
3804 else {
3805 /* first thread is the handler, there is no distributor here and workers are accepting queries */
3806 for (unsigned int threadId = 1; threadId <= g_numWorkerThreads; threadId++) {
3807 auto& deferredAdds = s_threadInfos.at(threadId).deferredAdds;
adb6cd72 3808 auto& tcpSockets = s_threadInfos.at(threadId).tcpSockets;
b243ca3b 3809 makeUDPServerSockets(deferredAdds);
adb6cd72 3810 makeTCPServerSockets(deferredAdds, tcpSockets);
b243ca3b 3811 }
810ff705
RG
3812 }
3813 }
3814 else {
c47f201b 3815 std::set<int> tcpSockets;
b243ca3b
RG
3816 /* we don't have reuseport so we can only open one socket per
3817 listening addr:port and everyone will listen on it */
3818 makeUDPServerSockets(g_deferredAdds);
c47f201b
RG
3819 makeTCPServerSockets(g_deferredAdds, tcpSockets);
3820
3821 /* every listener (so distributor if g_weDistributeQueries, workers otherwise)
3822 needs to listen to the shared sockets */
3823 if (g_weDistributeQueries) {
3824 /* first thread is the handler, then distributors */
3825 for (unsigned int threadId = 1; threadId <= g_numDistributorThreads; threadId++) {
3826 s_threadInfos.at(threadId).tcpSockets = tcpSockets;
3827 }
3828 }
3829 else {
3830 /* first thread is the handler, there is no distributor here and workers are accepting queries */
3831 for (unsigned int threadId = 1; threadId <= g_numWorkerThreads; threadId++) {
3832 s_threadInfos.at(threadId).tcpSockets = tcpSockets;
3833 }
3834 }
810ff705 3835 }
815099b2 3836
af1377b7
NC
3837#ifdef NOD_ENABLED
3838 // Setup newly observed domain globals
3839 setupNODGlobal();
3840#endif /* NOD_ENABLED */
3841
677e2a46
BH
3842 int forks;
3843 for(forks = 0; forks < ::arg().asNum("processes") - 1; ++forks) {
1bc3c142
BH
3844 if(!fork()) // we are child
3845 break;
3846 }
3ddb9247 3847
f7c1d4e3 3848 if(::arg().mustDo("daemon")) {
e6a9dde5
PL
3849 g_log<<Logger::Warning<<"Calling daemonize, going to background"<<endl;
3850 g_log.toConsole(Logger::Critical);
f7c1d4e3
BH
3851 daemonize();
3852 }
3853 signal(SIGUSR1,usr1Handler);
3854 signal(SIGUSR2,usr2Handler);
3855 signal(SIGPIPE,SIG_IGN);
810ff705 3856
a6414fdc 3857 checkOrFixFDS();
3ddb9247 3858
d1b28475
KM
3859#ifdef HAVE_LIBSODIUM
3860 if (sodium_init() == -1) {
e6a9dde5 3861 g_log<<Logger::Error<<"Unable to initialize sodium crypto library"<<endl;
d1b28475
KM
3862 exit(99);
3863 }
3864#endif
3865
3afde9b2
PL
3866 openssl_thread_setup();
3867 openssl_seed();
e97cb679
AT
3868 /* setup rng before chroot */
3869 dns_random_init();
3afde9b2 3870
bdbb07e0 3871 if(::arg()["server-id"].empty()) {
d0983bff 3872 ::arg().set("server-id") = myHostname;
bdbb07e0
PL
3873 }
3874
138435cb
BH
3875 int newgid=0;
3876 if(!::arg()["setgid"].empty())
3877 newgid=Utility::makeGidNumeric(::arg()["setgid"]);
3878 int newuid=0;
3879 if(!::arg()["setuid"].empty())
3880 newuid=Utility::makeUidNumeric(::arg()["setuid"]);
3881
f1d6a7ce
KM
3882 Utility::dropGroupPrivs(newuid, newgid);
3883
138435cb 3884 if (!::arg()["chroot"].empty()) {
75336810
PL
3885#ifdef HAVE_SYSTEMD
3886 char *ns;
3887 ns = getenv("NOTIFY_SOCKET");
3888 if (ns != nullptr) {
e6a9dde5 3889 g_log<<Logger::Error<<"Unable to chroot when running from systemd. Please disable chroot= or set the 'Type' for this service to 'simple'"<<endl;
75336810
PL
3890 exit(1);
3891 }
3892#endif
138435cb 3893 if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
e6a9dde5 3894 g_log<<Logger::Error<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror (errno)<<", exiting"<<endl;
138435cb
BH
3895 exit(1);
3896 }
f0f3f0b0 3897 else
377602e3 3898 g_log<<Logger::Info<<"Chrooted to '"<<::arg()["chroot"]<<"'"<<endl;
138435cb
BH
3899 }
3900
f0f3f0b0
PL
3901 s_pidfname=::arg()["socket-dir"]+"/"+s_programname+".pid";
3902 if(!s_pidfname.empty())
3903 unlink(s_pidfname.c_str()); // remove possible old pid file
3904 writePid();
3905
3906 makeControlChannelSocket( ::arg().asNum("processes") > 1 ? forks : -1);
3907
f1d6a7ce 3908 Utility::dropUserPrivs(newuid);
1f2b341e
RG
3909 try {
3910 /* we might still have capabilities remaining, for example if we have been started as root
3911 without --setuid (please don't do that) or as an unprivileged user with ambient capabilities
3912 like CAP_NET_BIND_SERVICE.
3913 */
3914 dropCapabilities();
3915 }
3916 catch(const std::exception& e) {
3917 g_log<<Logger::Warning<<e.what()<<endl;
3918 }
c0063e60 3919
e6ec15bf
RG
3920 startLuaConfigDelayedThreads(delayedLuaThreads, g_luaconfs.getCopy().generation);
3921
49a699c4 3922 makeThreadPipes();
3ddb9247 3923
5d4dd7fe
BH
3924 g_tcpTimeout=::arg().asNum("client-tcp-timeout");
3925 g_maxTCPPerClient=::arg().asNum("max-tcp-per-client");
fde296a3 3926 g_tcpMaxQueriesPerConn=::arg().asNum("max-tcp-queries-per-connection");
a5886e6a 3927 s_maxUDPQueriesPerRound=::arg().asNum("max-udp-queries-per-round");
343257a4 3928
563517f3
RG
3929 blacklistStats(StatComponent::API, ::arg()["stats-api-blacklist"]);
3930 blacklistStats(StatComponent::Carbon, ::arg()["stats-carbon-blacklist"]);
3931 blacklistStats(StatComponent::RecControl, ::arg()["stats-rec-control-blacklist"]);
3932 blacklistStats(StatComponent::SNMP, ::arg()["stats-snmp-blacklist"]);
72259676 3933
d705aad9
RG
3934 if (::arg().mustDo("snmp-agent")) {
3935 g_snmpAgent = std::make_shared<RecursorSNMPAgent>("recursor", ::arg()["snmp-master-socket"]);
3936 g_snmpAgent->run();
3937 }
3938
b47026fd 3939 int port = ::arg().asNum("udp-source-port-min");
58da9034 3940 if(port < 1024 || port > 65535){
e6a9dde5 3941 g_log<<Logger::Error<<"Unable to launch, udp-source-port-min is not a valid port number"<<endl;
bf6f28ca
CHB
3942 exit(99); // this isn't going to fix itself either
3943 }
3944 s_minUdpSourcePort = port;
b47026fd 3945 port = ::arg().asNum("udp-source-port-max");
58da9034 3946 if(port < 1024 || port > 65535 || port < s_minUdpSourcePort){
e6a9dde5 3947 g_log<<Logger::Error<<"Unable to launch, udp-source-port-max is not a valid port number or is smaller than udp-source-port-min"<<endl;
bf6f28ca
CHB
3948 exit(99); // this isn't going to fix itself either
3949 }
3950 s_maxUdpSourcePort = port;
3951 std::vector<string> parts {};
b47026fd 3952 stringtok(parts, ::arg()["udp-source-port-avoid"], ", ");
bf6f28ca
CHB
3953 for (const auto &part : parts)
3954 {
3955 port = std::stoi(part);
58da9034 3956 if(port < 1024 || port > 65535){
e6a9dde5 3957 g_log<<Logger::Error<<"Unable to launch, udp-source-port-avoid contains an invalid port number: "<<part<<endl;
bf6f28ca
CHB
3958 exit(99); // this isn't going to fix itself either
3959 }
3960 s_avoidUdpSourcePorts.insert(port);
3961 }
3962
b243ca3b 3963 unsigned int currentThreadId = 1;
8fd25133 3964 const auto cpusMap = parseCPUMap();
d77abca1 3965
c3828c03 3966 if(g_numThreads == 1) {
e6a9dde5 3967 g_log<<Logger::Warning<<"Operating unthreaded"<<endl;
6b6720de
PL
3968#ifdef HAVE_SYSTEMD
3969 sd_notify(0, "READY=1");
3970#endif
b243ca3b
RG
3971
3972 /* This thread handles the web server, carbon, statistics and the control channel */
3973 auto& handlerInfos = s_threadInfos.at(0);
3974 handlerInfos.isHandler = true;
c390b2da 3975 handlerInfos.thread = std::thread(recursorThread, 0, "main");
b243ca3b
RG
3976
3977 setCPUMap(cpusMap, currentThreadId, pthread_self());
3978
3979 auto& infos = s_threadInfos.at(currentThreadId);
3980 infos.isListener = true;
3981 infos.isWorker = true;
c390b2da 3982 recursorThread(currentThreadId++, "worker");
76698c6e
BH
3983 }
3984 else {
8fd25133 3985
b243ca3b
RG
3986 if (g_weDistributeQueries) {
3987 g_log<<Logger::Warning<<"Launching "<< g_numDistributorThreads <<" distributor threads"<<endl;
3988 for(unsigned int n=0; n < g_numDistributorThreads; ++n) {
3989 auto& infos = s_threadInfos.at(currentThreadId);
3990 infos.isListener = true;
c390b2da 3991 infos.thread = std::thread(recursorThread, currentThreadId++, "distr");
b243ca3b
RG
3992
3993 setCPUMap(cpusMap, currentThreadId, infos.thread.native_handle());
3994 }
3995 }
8fd25133 3996
62b549e0
RG
3997 g_log<<Logger::Warning<<"Launching "<< g_numWorkerThreads <<" worker threads"<<endl;
3998
b243ca3b
RG
3999 for(unsigned int n=0; n < g_numWorkerThreads; ++n) {
4000 auto& infos = s_threadInfos.at(currentThreadId);
4001 infos.isListener = g_weDistributeQueries ? false : true;
4002 infos.isWorker = true;
c390b2da 4003 infos.thread = std::thread(recursorThread, currentThreadId++, "worker");
b243ca3b
RG
4004
4005 setCPUMap(cpusMap, currentThreadId, infos.thread.native_handle());
76698c6e 4006 }
b243ca3b 4007
6b6720de
PL
4008#ifdef HAVE_SYSTEMD
4009 sd_notify(0, "READY=1");
4010#endif
b243ca3b
RG
4011
4012 /* This thread handles the web server, carbon, statistics and the control channel */
4013 auto& infos = s_threadInfos.at(0);
4014 infos.isHandler = true;
c390b2da 4015 infos.thread = std::thread(recursorThread, 0, "web+stat");
b243ca3b
RG
4016
4017 s_threadInfos.at(0).thread.join();
bb4bdbaf 4018 }
bb4bdbaf
BH
4019 return 0;
4020}
4021
c390b2da 4022static void* recursorThread(unsigned int n, const string& threadName)
bb4bdbaf
BH
4023try
4024{
d77abca1 4025 t_id=n;
b243ca3b 4026 auto& threadInfo = s_threadInfos.at(t_id);
c390b2da
PL
4027
4028 static string threadPrefix = "pdns-r/";
519f5484 4029 setThreadName(threadPrefix + threadName);
c390b2da 4030
49a699c4 4031 SyncRes tmp(g_now); // make sure it allocates tsstorage before we do anything, like primeHints or so..
a712cb56 4032 SyncRes::setDomainMap(g_initialDomainMap);
49a699c4 4033 t_allowFrom = g_initialAllowFrom;
f26bf547
RG
4034 t_udpclientsocks = std::unique_ptr<UDPClientSocks>(new UDPClientSocks());
4035 t_tcpClientCounts = std::unique_ptr<tcpClientCounts_t>(new tcpClientCounts_t());
49a699c4 4036 primeHints();
3ddb9247 4037
f26bf547 4038 t_packetCache = std::unique_ptr<RecursorPacketCache>(new RecursorPacketCache());
3ddb9247 4039
e6a9dde5 4040 g_log<<Logger::Warning<<"Done priming cache with root hints"<<endl;
3ddb9247 4041
af1377b7 4042#ifdef NOD_ENABLED
41c542ec
NC
4043 if (threadInfo.isWorker)
4044 setupNODThread();
af1377b7 4045#endif /* NOD_ENABLED */
c1751a59
RG
4046
4047 /* the listener threads handle TCP queries */
4048 if(threadInfo.isWorker || threadInfo.isListener) {
5b388d28
PD
4049 try {
4050 if(!::arg()["lua-dns-script"].empty()) {
4051 t_pdl = std::make_shared<RecursorLua4>();
4052 t_pdl->loadFile(::arg()["lua-dns-script"]);
4053 g_log<<Logger::Warning<<"Loaded 'lua' script from '"<<::arg()["lua-dns-script"]<<"'"<<endl;
4054 }
4055 }
4056 catch(std::exception &e) {
4057 g_log<<Logger::Error<<"Failed to load 'lua' script from '"<<::arg()["lua-dns-script"]<<"': "<<e.what()<<endl;
4058 _exit(99);
674cf0f6 4059 }
674cf0f6 4060 }
3ddb9247 4061
f8f243b0 4062 unsigned int ringsize=::arg().asNum("stats-ringbuffer-entries") / g_numWorkerThreads;
92011b8f 4063 if(ringsize) {
f26bf547 4064 t_remotes = std::unique_ptr<addrringbuf_t>(new addrringbuf_t());
b243ca3b
RG
4065 if(g_weDistributeQueries)
4066 t_remotes->set_capacity(::arg().asNum("stats-ringbuffer-entries") / g_numDistributorThreads);
f8f243b0 4067 else
3ddb9247 4068 t_remotes->set_capacity(ringsize);
f26bf547 4069 t_servfailremotes = std::unique_ptr<addrringbuf_t>(new addrringbuf_t());
3ddb9247 4070 t_servfailremotes->set_capacity(ringsize);
66f2e6ad
KM
4071 t_bogusremotes = std::unique_ptr<addrringbuf_t>(new addrringbuf_t());
4072 t_bogusremotes->set_capacity(ringsize);
f26bf547 4073 t_largeanswerremotes = std::unique_ptr<addrringbuf_t>(new addrringbuf_t());
3ddb9247 4074 t_largeanswerremotes->set_capacity(ringsize);
621ccf89 4075 t_timeouts = std::unique_ptr<addrringbuf_t>(new addrringbuf_t());
4076 t_timeouts->set_capacity(ringsize);
92011b8f 4077
f26bf547 4078 t_queryring = std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t> > >(new boost::circular_buffer<pair<DNSName, uint16_t> >());
3ddb9247 4079 t_queryring->set_capacity(ringsize);
f26bf547 4080 t_servfailqueryring = std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t> > >(new boost::circular_buffer<pair<DNSName, uint16_t> >());
3ddb9247 4081 t_servfailqueryring->set_capacity(ringsize);
66f2e6ad
KM
4082 t_bogusqueryring = std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t> > >(new boost::circular_buffer<pair<DNSName, uint16_t> >());
4083 t_bogusqueryring->set_capacity(ringsize);
92011b8f 4084 }
3ddb9247 4085
f26bf547 4086 MT=std::unique_ptr<MTasker<PacketID,string> >(new MTasker<PacketID,string>(::arg().asNum("stack-size")));
144040be 4087 threadInfo.mt = MT.get();
3ddb9247 4088
63341e8d
RG
4089#ifdef HAVE_PROTOBUF
4090 /* start protobuf export threads if needed */
4091 auto luaconfsLocal = g_luaconfs.getLocal();
4092 checkProtobufExport(luaconfsLocal);
4093 checkOutgoingProtobufExport(luaconfsLocal);
4094#endif /* HAVE_PROTOBUF */
4095
bb4bdbaf
BH
4096 PacketID pident;
4097
4098 t_fdm=getMultiplexer();
d77abca1 4099
b243ca3b 4100 if(threadInfo.isHandler) {
d07bf7ff 4101 if(::arg().mustDo("webserver")) {
e6a9dde5 4102 g_log<<Logger::Warning << "Enabling web server" << endl;
8989097d 4103 try {
1ce57618 4104 new RecursorWebServer(t_fdm);
8989097d
CH
4105 }
4106 catch(PDNSException &e) {
e6a9dde5 4107 g_log<<Logger::Error<<"Exception: "<<e.reason<<endl;
8989097d
CH
4108 exit(99);
4109 }
f3d1d67b 4110 }
377602e3 4111 g_log<<Logger::Info<<"Enabled '"<< t_fdm->getName() << "' multiplexer"<<endl;
f3d1d67b 4112 }
810ff705 4113 else {
d77abca1 4114
b243ca3b
RG
4115 t_fdm->addReadFD(threadInfo.pipes.readToThread, handlePipeRequest);
4116 t_fdm->addReadFD(threadInfo.pipes.readQueriesToThread, handlePipeRequest);
4117
4118 if (threadInfo.isListener) {
4119 if (g_reusePort) {
4120 /* then every listener has its own FDs */
4121 for(const auto deferred : threadInfo.deferredAdds) {
4122 t_fdm->addReadFD(deferred.first, deferred.second);
4123 }
810ff705 4124 }
b243ca3b
RG
4125 else {
4126 /* otherwise all listeners are listening on the same ones */
4127 for(const auto deferred : g_deferredAdds) {
4128 t_fdm->addReadFD(deferred.first, deferred.second);
d77abca1
RG
4129 }
4130 }
4131 }
810ff705 4132 }
3ddb9247 4133
b0b37121 4134 registerAllStats();
d77abca1 4135
b243ca3b 4136 if(threadInfo.isHandler) {
674cf0f6
BH
4137 t_fdm->addReadFD(s_rcc.d_fd, handleRCC); // control channel
4138 }
1bc3c142 4139
f7c1d4e3 4140 unsigned int maxTcpClients=::arg().asNum("max-tcp-clients");
3ddb9247 4141
f7c1d4e3 4142 bool listenOnTCP(true);
49a699c4 4143
cb1523d1 4144 time_t last_stat = 0;
a2f87dd1 4145 time_t last_carbon=0, last_lua_maintenance=0;
2c78bd57 4146 time_t carbonInterval=::arg().asNum("carbon-interval");
a2f87dd1 4147 time_t luaMaintenanceInterval=::arg().asNum("lua-maintenance-interval");
ac0995bb 4148 counter.store(0); // used to periodically execute certain tasks
f7c1d4e3 4149 for(;;) {
ac0e821b 4150 while(MT->schedule(&g_now)); // MTasker letting the mthreads do their thing
3ddb9247 4151
3427fa8a
BH
4152 if(!(counter%500)) {
4153 MT->makeThread(houseKeeping, 0);
f7c1d4e3
BH
4154 }
4155
d2392145 4156 if(!(counter%55)) {
d8f6d49f 4157 typedef vector<pair<int, FDMultiplexer::funcparam_t> > expired_t;
bb4bdbaf 4158 expired_t expired=t_fdm->getTimeouts(g_now);
3ddb9247 4159
f7c1d4e3 4160 for(expired_t::iterator i=expired.begin() ; i != expired.end(); ++i) {
cd989c87 4161 shared_ptr<TCPConnection> conn=any_cast<shared_ptr<TCPConnection> >(i->second);
4957a608 4162 if(g_logCommonErrors)
e6a9dde5 4163 g_log<<Logger::Warning<<"Timeout from remote TCP client "<< conn->d_remote.toStringWithPort() <<endl;
4957a608 4164 t_fdm->removeReadFD(i->first);
f7c1d4e3
BH
4165 }
4166 }
3ddb9247 4167
f7c1d4e3
BH
4168 counter++;
4169
b243ca3b 4170 if(threadInfo.isHandler) {
cb1523d1
RG
4171 if(statsWanted || (g_statisticsInterval > 0 && (g_now.tv_sec - last_stat) >= g_statisticsInterval)) {
4172 doStats();
4173 last_stat = g_now.tv_sec;
4174 }
f7c1d4e3 4175
cb1523d1 4176 Utility::gettimeofday(&g_now, 0);
2c78bd57 4177
cb1523d1
RG
4178 if((g_now.tv_sec - last_carbon) >= carbonInterval) {
4179 MT->makeThread(doCarbonDump, 0);
4180 last_carbon = g_now.tv_sec;
4181 }
2c78bd57 4182 }
2a0276a9 4183 if (t_pdl != nullptr) {
9adbe790 4184 // lua-dns-script directive is present, call the maintenance callback if needed
c1751a59
RG
4185 /* remember that the listener threads handle TCP queries */
4186 if (threadInfo.isWorker || threadInfo.isListener) {
2a0276a9
CHB
4187 // Only on threads processing queries
4188 if(g_now.tv_sec - last_lua_maintenance >= luaMaintenanceInterval) {
4189 t_pdl->maintenance();
4190 last_lua_maintenance = g_now.tv_sec;
4191 }
9adbe790 4192 }
a2f87dd1 4193 }
2c78bd57 4194
bb4bdbaf 4195 t_fdm->run(&g_now);
3ea54bf0 4196 // 'run' updates g_now for us
f7c1d4e3 4197
b243ca3b 4198 if(threadInfo.isListener) {
5c889cf5 4199 if(listenOnTCP) {
c47f201b
RG
4200 if(TCPConnection::getCurrentConnections() > maxTcpClients) { // shutdown, too many connections
4201 for(const auto fd : threadInfo.tcpSockets) {
4202 t_fdm->removeReadFD(fd);
b243ca3b 4203 }
c47f201b
RG
4204 listenOnTCP=false;
4205 }
f7c1d4e3 4206 }
5c889cf5 4207 else {
c47f201b
RG
4208 if(TCPConnection::getCurrentConnections() <= maxTcpClients) { // reenable
4209 for(const auto fd : threadInfo.tcpSockets) {
4210 t_fdm->addReadFD(fd, handleNewTCPQuestion);
b243ca3b 4211 }
c47f201b
RG
4212 listenOnTCP=true;
4213 }
f7c1d4e3
BH
4214 }
4215 }
4216 }
4217}
3f81d239 4218catch(PDNSException &ae) {
e6a9dde5 4219 g_log<<Logger::Error<<"Exception: "<<ae.reason<<endl;
bb4bdbaf
BH
4220 return 0;
4221}
4222catch(std::exception &e) {
e6a9dde5 4223 g_log<<Logger::Error<<"STL Exception: "<<e.what()<<endl;
bb4bdbaf
BH
4224 return 0;
4225}
4226catch(...) {
e6a9dde5 4227 g_log<<Logger::Error<<"any other exception in main: "<<endl;
bb4bdbaf
BH
4228 return 0;
4229}
4230
51e2144e 4231
3ddb9247 4232int main(int argc, char **argv)
288f4aa9 4233{
dbd23fc2
BH
4234 g_argc = argc;
4235 g_argv = argv;
5e3de507 4236 g_stats.startupTime=time(0);
b51ef4f9 4237 Utility::srandom();
3e135495 4238 versionSetProduct(ProductRecursor);
8a63d3ce 4239 reportBasicTypes();
0007c2e5 4240 reportOtherTypes();
ea634573 4241
22030c37 4242 int ret = EXIT_SUCCESS;
caa6eefa 4243
288f4aa9 4244 try {
f888311c 4245 ::arg().set("stack-size","stack size per mthread")="200000";
2e3d8a19 4246 ::arg().set("soa-minimum-ttl","Don't change")="0";
2e3d8a19 4247 ::arg().set("no-shuffle","Don't change")="off";
2e3d8a19 4248 ::arg().set("local-port","port to listen on")="53";
32252594 4249 ::arg().set("local-address","IP addresses to listen on, separated by spaces or commas. Also accepts ports.")="127.0.0.1";
fec7dd5a 4250 ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options")="no";
77499b05 4251 ::arg().set("trace","if we should output heaps of logging. set to 'fail' to only log failing domains")="off";
a6415142 4252 ::arg().set("dnssec", "DNSSEC mode: off/process-no-validate (default)/process/log-fail/validate")="process-no-validate";
c87e1876 4253 ::arg().set("dnssec-log-bogus", "Log DNSSEC bogus validations")="no";
13c46e62 4254 ::arg().set("signature-inception-skew", "Allow the signature inception to be off by this number of seconds")="60";
d3f809bf 4255 ::arg().set("daemon","Operate as a daemon")="no";
191f2e47 4256 ::arg().setSwitch("write-pid","Write a PID file")="yes";
9afa8662 4257 ::arg().set("loglevel","Amount of logging. Higher is more. Do not set below 3")="6";
b6cfa948 4258 ::arg().set("disable-syslog","Disable logging to syslog, useful when running inside a supervisor that logs stdout")="no";
b18fa400 4259 ::arg().set("log-timestamp","Print timestamps in log lines, useful to disable when running with a tool that timestamps stdout already")="yes";
22e0810c 4260 ::arg().set("log-common-errors","If we should log rather common errors")="no";
2e3d8a19
BH
4261 ::arg().set("chroot","switch to chroot jail")="";
4262 ::arg().set("setgid","If set, change group id to this gid for more security")="";
4263 ::arg().set("setuid","If set, change user id to this uid for more security")="";
c83ee49d 4264 ::arg().set("network-timeout", "Wait this number of milliseconds for network i/o")="1500";
bb4bdbaf 4265 ::arg().set("threads", "Launch this number of threads")="2";
b243ca3b 4266 ::arg().set("distributor-threads", "Launch this number of distributor threads, distributing queries to other threads")="0";
adabfcb9 4267 ::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 4268 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
d07bf7ff 4269 ::arg().set("api-config-dir", "Directory where REST API stores config and zones") = "";
479e0976 4270 ::arg().set("api-key", "Static pre-shared authentication key for access to the REST API") = "";
479e0976 4271 ::arg().setSwitch("webserver", "Start a webserver (for REST API)") = "no";
d07bf7ff
PL
4272 ::arg().set("webserver-address", "IP Address of webserver to listen on") = "127.0.0.1";
4273 ::arg().set("webserver-port", "Port of webserver to listen on") = "8082";
4274 ::arg().set("webserver-password", "Password required for accessing the webserver") = "";
be3e1477 4275 ::arg().set("webserver-allow-from","Webserver access is only allowed from these subnets")="127.0.0.1,::1";
8ca656a8 4276 ::arg().set("webserver-loglevel", "Amount of logging in the webserver (none, normal, detailed)") = "normal";
cc08b5a9 4277 ::arg().set("carbon-ourname", "If set, overrides our reported hostname for carbon stats")="";
e12f8407 4278 ::arg().set("carbon-server", "If set, send metrics in carbon (graphite) format to this server IP address")="";
2c78bd57 4279 ::arg().set("carbon-interval", "Number of seconds between carbon (graphite) updates")="30";
f7a645ec
RG
4280 ::arg().set("carbon-namespace", "If set overwrites the first part of the carbon string")="pdns";
4281 ::arg().set("carbon-instance", "If set overwrites the the instance name default")="recursor";
4282
0ec489bf 4283 ::arg().set("statistics-interval", "Number of seconds between printing of recursor statistics, 0 to disable")="1800";
c038218b 4284 ::arg().set("quiet","Suppress logging of questions and answers")="";
f27e6356 4285 ::arg().set("logging-facility","Facility to log messages as. 0 corresponds to local0")="";
2e3d8a19 4286 ::arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR;
fdbf35ac
BH
4287 ::arg().set("socket-owner","Owner of socket")="";
4288 ::arg().set("socket-group","Group of socket")="";
4289 ::arg().set("socket-mode", "Permissions for socket")="";
3ddb9247 4290
f0f3f0b0 4291 ::arg().set("socket-dir",string("Where the controlsocket will live, ")+LOCALSTATEDIR+" when unset and not chrooted" )="";
2e3d8a19
BH
4292 ::arg().set("delegation-only","Which domains we only accept delegations from")="";
4293 ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
d4fb76e9 4294 ::arg().set("query-local-address6","Source IPv6 address for sending queries. IF UNSET, IPv6 WILL NOT BE USED FOR OUTGOING QUERIES")="";
2e3d8a19 4295 ::arg().set("client-tcp-timeout","Timeout in seconds when talking to TCP clients")="2";
85c32340 4296 ::arg().set("max-mthreads", "Maximum number of simultaneous Mtasker threads")="2048";
2e3d8a19 4297 ::arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
324dc148 4298 ::arg().set("server-down-max-fails","Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )")="64";
979edd70 4299 ::arg().set("server-down-throttle-time","Number of seconds to throttle all queries to a server after being marked as down")="60";
2e3d8a19 4300 ::arg().set("hint-file", "If set, load root hints from this file")="";
b45eb27c 4301 ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="1000000";
a9af3782 4302 ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
b9473937 4303 ::arg().set("max-cache-bogus-ttl", "maximum number of seconds to keep a Bogus (positive or negative) cached entry in memory")="3600";
c3e753c7 4304 ::arg().set("max-cache-ttl", "maximum number of seconds to keep a cached entry in memory")="86400";
1051f8a9 4305 ::arg().set("packetcache-ttl", "maximum number of seconds to keep a cached entry in packetcache")="3600";
927c12b0 4306 ::arg().set("max-packetcache-entries", "maximum number of entries to keep in the packetcache")="500000";
1051f8a9 4307 ::arg().set("packetcache-servfail-ttl", "maximum number of seconds to keep a cached servfail entry in packetcache")="60";
950626be 4308 ::arg().set("server-id", "Returned when queried for 'id.server' TXT or NSID, defaults to hostname, set custom or 'disabled'")="";
92011b8f 4309 ::arg().set("stats-ringbuffer-entries", "maximum number of packets to store statistics for")="10000";
ba1a571d 4310 ::arg().set("version-string", "string reported on version.pdns or version.bind")=fullVersionString();
49a699c4 4311 ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")=LOCAL_NETS;
2c95fc65 4312 ::arg().set("allow-from-file", "If set, load allowed netmasks from this file")="";
51e2144e 4313 ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
3ddb9247 4314 ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=DONT_QUERY;
4e120339 4315 ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
fde296a3 4316 ::arg().set("max-tcp-queries-per-connection", "If set, maximum number of TCP queries in a TCP connection")="0";
0d5f0a9f 4317 ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
4ef015cd 4318 ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
5605c067 4319 ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
3e61e7f7 4320 ::arg().set("lua-config-file", "More powerful configuration options")="";
644dd1da 4321
5605c067 4322 ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
927c12b0
BH
4323 ::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs")="";
4324 ::arg().set("forward-zones-file", "File with (+)domain=ip pairs for forwarding")="";
5605c067 4325 ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts")="off";
ac0b4eb3 4326 ::arg().set("export-etc-hosts-search-suffix", "Also serve up the contents of /etc/hosts with this suffix")="";
3ea54bf0 4327 ::arg().set("etc-hosts-file", "Path to 'hosts' file")="/etc/hosts";
e498dac1 4328 ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="yes";
4485aa35 4329 ::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers")="";
a2f87dd1 4330 ::arg().set("lua-maintenance-interval", "Number of seconds between calls to the lua user defined maintenance() function")="1";
08f3f638 4331 ::arg().set("latency-statistic-size","Number of latency values to calculate the qa-latency average")="10000";
3ddb9247 4332 ::arg().setSwitch( "disable-packetcache", "Disable packetcache" )= "no";
35695d18 4333 ::arg().set("ecs-ipv4-bits", "Number of bits of IPv4 address to pass for EDNS Client Subnet")="24";
fd8898fb 4334 ::arg().set("ecs-ipv4-cache-bits", "Maximum number of bits of IPv4 mask to cache ECS response")="24";
35695d18 4335 ::arg().set("ecs-ipv6-bits", "Number of bits of IPv6 address to pass for EDNS Client Subnet")="56";
fd8898fb 4336 ::arg().set("ecs-ipv6-cache-bits", "Maximum number of bits of IPv6 mask to cache ECS response")="56";
5cf4b2e7 4337 ::arg().set("ecs-minimum-ttl-override", "Set under adverse conditions, a minimum TTL for records in ECS-specific answers")="0";
ed9019c9 4338 ::arg().set("ecs-cache-limit-ttl", "Minimum TTL to cache ECS response")="0";
3f975863 4339 ::arg().set("edns-subnet-whitelist", "List of netmasks and domains that we should enable EDNS subnet for")="";
2fe3354d 4340 ::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 4341 ::arg().set("ecs-scope-zero-address", "Address to send to whitelisted authoritative servers for incoming queries with ECS prefix-length source of 0")="";
a16c4536 4342 ::arg().setSwitch( "use-incoming-edns-subnet", "Pass along received EDNS Client Subnet information")="no";
e498dac1 4343 ::arg().setSwitch( "pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads")="yes";
4ca2d205 4344 ::arg().setSwitch( "root-nx-trust", "If set, believe that an NXDOMAIN from the root means the TLD does not exist")="yes";
e661a20b 4345 ::arg().setSwitch( "any-to-tcp","Answer ANY queries with tc=1, shunting to TCP" )="no";
b3adda56 4346 ::arg().setSwitch( "lowercase-outgoing","Force outgoing questions to lowercase")="no";
00b8cadc 4347 ::arg().setSwitch("gettag-needs-edns-options", "If EDNS Options should be extracted before calling the gettag() hook")="no";
54c36063
PL
4348 ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate")="1232";
4349 ::arg().set("edns-outgoing-bufsize", "Outgoing EDNS buffer size")="1232";
aadceba8 4350 ::arg().set("minimum-ttl-override", "Set under adverse conditions, a minimum TTL")="0";
173d790e 4351 ::arg().set("max-qperq", "Maximum outgoing queries per query")="50";
c5950146 4352 ::arg().set("max-total-msec", "Maximum total wall-clock time per query in milliseconds, 0 for unlimited")="7000";
7c3398aa 4353 ::arg().set("max-recursion-depth", "Maximum number of internal recursion calls per query, 0 for unlimited")="40";
78227847 4354 ::arg().set("max-udp-queries-per-round", "Maximum number of UDP queries processed per recvmsg() round, before returning back to normal processing")="10000";
a09a8ce0 4355
68e6df3c 4356 ::arg().set("include-dir","Include *.conf files from this directory")="";
d67620e4 4357 ::arg().set("security-poll-suffix","Domain name from which to query security update notifications")="secpoll.powerdns.com.";
2332f42d 4358
4359 ::arg().setSwitch("reuseport","Enable SO_REUSEPORT allowing multiple recursors processes to listen to 1 address")="no";
2e3d8a19 4360
d705aad9 4361 ::arg().setSwitch("snmp-agent", "If set, register as an SNMP agent")="no";
396f126e 4362 ::arg().set("snmp-master-socket", "If set and snmp-agent is set, the socket to use to register to the SNMP master")="";
d705aad9 4363
72259676
RG
4364 std::string defaultBlacklistedStats = "cache-bytes, packetcache-bytes, special-memory-usage";
4365 for (size_t idx = 0; idx < 32; idx++) {
4366 defaultBlacklistedStats += ", ecs-v4-response-bits-" + std::to_string(idx + 1);
4367 }
4368 for (size_t idx = 0; idx < 128; idx++) {
4369 defaultBlacklistedStats += ", ecs-v6-response-bits-" + std::to_string(idx + 1);
4370 }
563517f3
RG
4371 ::arg().set("stats-api-blacklist", "List of statistics that are disabled when retrieving the complete list of statistics via the API")=defaultBlacklistedStats;
4372 ::arg().set("stats-carbon-blacklist", "List of statistics that are prevented from being exported via Carbon")=defaultBlacklistedStats;
4373 ::arg().set("stats-rec-control-blacklist", "List of statistics that are prevented from being exported via rec_control get-all")=defaultBlacklistedStats;
4374 ::arg().set("stats-snmp-blacklist", "List of statistics that are prevented from being exported via SNMP")=defaultBlacklistedStats;
d705aad9 4375
0735b17e 4376 ::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 4377 ::arg().set("nsec3-max-iterations", "Maximum number of iterations allowed for an NSEC3 record")="2500";
0735b17e 4378
8fd25133
RG
4379 ::arg().set("cpu-map", "Thread to CPU mapping, space separated thread-id=cpu1,cpu2..cpuN pairs")="";
4380
98d36505
RG
4381 ::arg().setSwitch("log-rpz-changes", "Log additions and removals to RPZ zones at Info level")="no";
4382
5cc8371b 4383 ::arg().set("xpf-allow-from","XPF information is only processed from these subnets")="";
59cb4a79 4384 ::arg().set("xpf-rr-code","XPF option code to use")="0";
5cc8371b 4385
58da9034 4386 ::arg().set("udp-source-port-min", "Minimum UDP port to bind on")="1024";
b47026fd
CHB
4387 ::arg().set("udp-source-port-max", "Maximum UDP port to bind on")="65535";
4388 ::arg().set("udp-source-port-avoid", "List of comma separated UDP port number to avoid")="11211";
e97cb679 4389 ::arg().set("rng", "Specify random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.")="auto";
d6f3fcfa 4390 ::arg().set("public-suffix-list-file", "Path to the Public Suffix List file, if any")="";
144040be 4391 ::arg().set("distribution-load-factor", "The load factor used when PowerDNS is distributing queries to worker threads")="0.0";
af1377b7
NC
4392#ifdef NOD_ENABLED
4393 ::arg().set("new-domain-tracking", "Track newly observed domains (i.e. never seen before).")="no";
4394 ::arg().set("new-domain-log", "Log newly observed domains.")="yes";
4395 ::arg().set("new-domain-lookup", "Perform a DNS lookup newly observed domains as a subdomain of the configured domain")="";
4396 ::arg().set("new-domain-history-dir", "Persist new domain tracking data here to persist between restarts")=string(NODCACHEDIR)+"/nod";
4397 ::arg().set("new-domain-whitelist", "List of domains (and implicitly all subdomains) which will never be considered a new domain")="";
b78727c6 4398 ::arg().set("new-domain-db-size", "Size of the DB used to track new domains in terms of number of cells. Defaults to 67108864")="67108864";
ca2526f5 4399 ::arg().set("new-domain-pb-tag", "If protobuf is configured, the tag to use for messages containing newly observed domains. Defaults to 'pdns-nod'")="pdns-nod";
41c542ec
NC
4400 ::arg().set("unique-response-tracking", "Track unique responses (tuple of query name, type and RR).")="no";
4401 ::arg().set("unique-response-log", "Log unique responses")="yes";
4402 ::arg().set("unique-response-history-dir", "Persist unique response tracking data here to persist between restarts")=string(NODCACHEDIR)+"/udr";
b78727c6 4403 ::arg().set("unique-response-db-size", "Size of the DB used to track unique responses in terms of number of cells. Defaults to 67108864")="67108864";
ca2526f5 4404 ::arg().set("unique-response-pb-tag", "If protobuf is configured, the tag to use for messages containing unique DNS responses. Defaults to 'pdns-udr'")="pdns-udr";
af1377b7 4405#endif /* NOD_ENABLED */
2e3d8a19 4406 ::arg().setCmd("help","Provide a helpful message");
ba1a571d 4407 ::arg().setCmd("version","Print version string");
d5141417 4408 ::arg().setCmd("config","Output blank configuration");
e6a9dde5 4409 g_log.toConsole(Logger::Info);
2e3d8a19 4410 ::arg().laxParse(argc,argv); // do a lax parse
c75a6a9e 4411
2d733c0f
CH
4412 string configname=::arg()["config-dir"]+"/recursor.conf";
4413 if(::arg()["config-name"]!="") {
4414 configname=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf";
5124de27 4415 s_programname+="-"+::arg()["config-name"];
2d733c0f
CH
4416 }
4417 cleanSlashes(configname);
5124de27 4418
5cc1ea1d
CH
4419 if(!::arg().getCommands().empty()) {
4420 cerr<<"Fatal: non-option on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl;
4421 exit(99);
4422 }
4423
577cf284
BH
4424 if(::arg().mustDo("config")) {
4425 cout<<::arg().configstring()<<endl;
4426 exit(0);
4427 }
4428
3ddb9247 4429 if(!::arg().file(configname.c_str()))
e6a9dde5 4430 g_log<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl;
c75a6a9e 4431
2e3d8a19 4432 ::arg().parse(argc,argv);
c836dc19 4433
2054afbb
CH
4434 if( !::arg()["chroot"].empty() && !::arg()["api-config-dir"].empty() ) {
4435 g_log<<Logger::Error<<"Using chroot and enabling the API is not possible"<<endl;
f0f3f0b0
PL
4436 exit(EXIT_FAILURE);
4437 }
4438
4439 if (::arg()["socket-dir"].empty()) {
4440 if (::arg()["chroot"].empty())
4441 ::arg().set("socket-dir") = LOCALSTATEDIR;
4442 else
4443 ::arg().set("socket-dir") = "/";
4444 }
4445
2e3d8a19 4446 ::arg().set("delegation-only")=toLower(::arg()["delegation-only"]);
562588a3 4447
b243ca3b
RG
4448 if(::arg().asNum("threads")==1) {
4449 if (::arg().mustDo("pdns-distributes-queries")) {
4450 g_log<<Logger::Warning<<"Only one thread, no need to distribute queries ourselves"<<endl;
4451 ::arg().set("pdns-distributes-queries")="no";
4452 }
4453 }
4454
4455 if(::arg().mustDo("pdns-distributes-queries") && ::arg().asNum("distributor-threads") <= 0) {
4456 g_log<<Logger::Warning<<"Asked to run with pdns-distributes-queries set but no distributor threads, raising to 1"<<endl;
4457 ::arg().set("distributor-threads")="1";
4458 }
4459
4460 if (!::arg().mustDo("pdns-distributes-queries")) {
4461 ::arg().set("distributor-threads")="0";
4462 }
61d74169 4463
2e3d8a19 4464 if(::arg().mustDo("help")) {
ff5ba4f9
WA
4465 cout<<"syntax:"<<endl<<endl;
4466 cout<<::arg().helpstring(::arg()["help"])<<endl;
4467 exit(0);
b636533b 4468 }
5e3de507 4469 if(::arg().mustDo("version")) {
ba1a571d 4470 showProductVersion();
3613a51c 4471 showBuildConfiguration();
67076869 4472 exit(0);
5e3de507 4473 }
b636533b 4474
34162f8f 4475 Logger::Urgency logUrgency = (Logger::Urgency)::arg().asNum("loglevel");
f48d7b65 4476
34162f8f
CH
4477 if (logUrgency < Logger::Error)
4478 logUrgency = Logger::Error;
f48d7b65 4479 if(!g_quiet && logUrgency < Logger::Info) { // Logger::Info=6, Logger::Debug=7
4480 logUrgency = Logger::Info; // if you do --quiet=no, you need Info to also see the query log
4481 }
e6a9dde5
PL
4482 g_log.setLoglevel(logUrgency);
4483 g_log.toConsole(logUrgency);
34162f8f 4484
f7c1d4e3 4485 serviceMain(argc, argv);
288f4aa9 4486 }
3f81d239 4487 catch(PDNSException &ae) {
e6a9dde5 4488 g_log<<Logger::Error<<"Exception: "<<ae.reason<<endl;
22030c37 4489 ret=EXIT_FAILURE;
288f4aa9 4490 }
fdbf35ac 4491 catch(std::exception &e) {
e6a9dde5 4492 g_log<<Logger::Error<<"STL Exception: "<<e.what()<<endl;
22030c37 4493 ret=EXIT_FAILURE;
288f4aa9
BH
4494 }
4495 catch(...) {
e6a9dde5 4496 g_log<<Logger::Error<<"any other exception in main: "<<endl;
22030c37 4497 ret=EXIT_FAILURE;
288f4aa9 4498 }
3ddb9247 4499
22030c37 4500 return ret;
288f4aa9 4501}