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