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