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