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