]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/rec-main.cc
updated KSK and ZSK Rollover procedures, small fixes in Algorithm Rollover procedure
[thirdparty/pdns.git] / pdns / recursordist / rec-main.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 #include <sys/stat.h>
23
24 #include "rec-main.hh"
25
26 #include "aggressive_nsec.hh"
27 #include "capabilities.hh"
28 #include "arguments.hh"
29 #include "dns_random.hh"
30 #include "rec_channel.hh"
31 #include "rec-tcpout.hh"
32 #include "version.hh"
33 #include "query-local-address.hh"
34 #include "validate-recursor.hh"
35 #include "pubsuffix.hh"
36 #include "opensslsigners.hh"
37 #include "ws-recursor.hh"
38 #include "rec-taskqueue.hh"
39 #include "secpoll-recursor.hh"
40 #include "logging.hh"
41
42 #ifdef NOD_ENABLED
43 #include "nod.hh"
44 #endif /* NOD_ENABLED */
45
46 #ifdef HAVE_LIBSODIUM
47 #include <sodium.h>
48 #endif
49
50 #ifdef HAVE_SYSTEMD
51 #include <systemd/sd-daemon.h>
52 #endif
53
54 static thread_local uint64_t t_protobufServersGeneration;
55 static thread_local uint64_t t_outgoingProtobufServersGeneration;
56
57 #ifdef HAVE_FSTRM
58 thread_local std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>> t_frameStreamServers{nullptr};
59 thread_local uint64_t t_frameStreamServersGeneration;
60 #endif /* HAVE_FSTRM */
61
62 string g_programname = "pdns_recursor";
63 string g_pidfname;
64 RecursorControlChannel g_rcc; // only active in the handler thread
65
66 #ifdef NOD_ENABLED
67 bool g_nodEnabled;
68 DNSName g_nodLookupDomain;
69 bool g_nodLog;
70 SuffixMatchNode g_nodDomainWL;
71 std::string g_nod_pbtag;
72 bool g_udrEnabled;
73 bool g_udrLog;
74 std::string g_udr_pbtag;
75 thread_local std::shared_ptr<nod::NODDB> t_nodDBp;
76 thread_local std::shared_ptr<nod::UniqueResponseDB> t_udrDBp;
77 #endif /* NOD_ENABLED */
78
79 std::atomic<bool> statsWanted;
80 uint32_t g_disthashseed;
81 bool g_useIncomingECS;
82 uint16_t g_xpfRRCode{0};
83 NetmaskGroup g_proxyProtocolACL;
84 boost::optional<ComboAddress> g_dns64Prefix{boost::none};
85 DNSName g_dns64PrefixReverse;
86 std::shared_ptr<SyncRes::domainmap_t> g_initialDomainMap; // new threads needs this to be setup
87 std::shared_ptr<NetmaskGroup> g_initialAllowFrom; // new thread needs to be setup with this
88 std::shared_ptr<NetmaskGroup> g_initialAllowNotifyFrom; // new threads need this to be setup
89 std::shared_ptr<notifyset_t> g_initialAllowNotifyFor; // new threads need this to be setup
90 bool g_logRPZChanges{false};
91 static time_t s_statisticsInterval;
92 bool g_addExtendedResolutionDNSErrors;
93 static std::atomic<uint32_t> s_counter;
94 int g_argc;
95 char** g_argv;
96
97 /* without reuseport, all listeners share the same sockets */
98 deferredAdd_t g_deferredAdds;
99
100 /* first we have the handler thread, t_id == 0 (some other
101 helper threads like SNMP might have t_id == 0 as well)
102 then the distributor threads if any
103 and finally the workers */
104 std::vector<RecThreadInfo> RecThreadInfo::s_threadInfos;
105
106 bool RecThreadInfo::s_weDistributeQueries; // if true, 1 or more threads listen on the incoming query sockets and distribute them to workers
107 unsigned int RecThreadInfo::s_numDistributorThreads;
108 unsigned int RecThreadInfo::s_numWorkerThreads;
109 thread_local unsigned int RecThreadInfo::t_id;
110
111 static std::map<unsigned int, std::set<int>> parseCPUMap()
112 {
113 std::map<unsigned int, std::set<int>> result;
114
115 const std::string value = ::arg()["cpu-map"];
116
117 if (!value.empty() && !isSettingThreadCPUAffinitySupported()) {
118 g_log << Logger::Warning << "CPU mapping requested but not supported, skipping" << endl;
119 return result;
120 }
121
122 std::vector<std::string> parts;
123
124 stringtok(parts, value, " \t");
125
126 for (const auto& part : parts) {
127 if (part.find('=') == string::npos)
128 continue;
129
130 try {
131 auto headers = splitField(part, '=');
132 boost::trim(headers.first);
133 boost::trim(headers.second);
134
135 auto threadId = pdns::checked_stoi<unsigned int>(headers.first);
136 std::vector<std::string> cpus;
137
138 stringtok(cpus, headers.second, ",");
139
140 for (const auto& cpu : cpus) {
141 int cpuId = std::stoi(cpu);
142
143 result[threadId].insert(cpuId);
144 }
145 }
146 catch (const std::exception& e) {
147 g_log << Logger::Error << "Error parsing cpu-map entry '" << part << "': " << e.what() << endl;
148 }
149 }
150
151 return result;
152 }
153
154 static void setCPUMap(const std::map<unsigned int, std::set<int>>& cpusMap, unsigned int n, pthread_t tid)
155 {
156 const auto& cpuMapping = cpusMap.find(n);
157 if (cpuMapping == cpusMap.cend()) {
158 return;
159 }
160 int rc = mapThreadToCPUList(tid, cpuMapping->second);
161 if (rc == 0) {
162 g_log << Logger::Info << "CPU affinity for thread " << n << " has been set to CPU map:";
163 for (const auto cpu : cpuMapping->second) {
164 g_log << Logger::Info << " " << cpu;
165 }
166 g_log << Logger::Info << endl;
167 }
168 else {
169 g_log << Logger::Warning << "Error setting CPU affinity for thread " << n << " to CPU map:";
170 for (const auto cpu : cpuMapping->second) {
171 g_log << Logger::Info << " " << cpu;
172 }
173 g_log << Logger::Info << ' ' << strerror(rc) << endl;
174 }
175 }
176
177 static void recursorThread();
178
179 void RecThreadInfo::start(unsigned int id, const string& tname, const std::map<unsigned int, std::set<int>>& cpusMap)
180 {
181 name = tname;
182 thread = std::thread([id, tname] {
183 t_id = id;
184 const string threadPrefix = "rec/";
185 setThreadName(threadPrefix + tname);
186 recursorThread();
187 });
188 setCPUMap(cpusMap, id, thread.native_handle());
189 }
190
191 int RecThreadInfo::runThreads()
192 {
193 int ret = EXIT_SUCCESS;
194 unsigned int currentThreadId = 1;
195 const auto cpusMap = parseCPUMap();
196
197 if (RecThreadInfo::numDistributors() + RecThreadInfo::numWorkers() == 1) {
198 g_log << Logger::Warning << "Operating with single distributor/worker thread" << endl;
199
200 #ifdef HAVE_SYSTEMD
201 sd_notify(0, "READY=1");
202 #endif
203
204 /* This thread handles the web server, carbon, statistics and the control channel */
205 auto& handlerInfo = RecThreadInfo::info(0);
206 handlerInfo.setHandler();
207 handlerInfo.start(0, "web+stat", cpusMap);
208 auto& taskInfo = RecThreadInfo::info(2);
209 taskInfo.setTaskThread();
210 taskInfo.start(2, "taskThread", cpusMap);
211
212 auto& info = RecThreadInfo::info(currentThreadId);
213 info.setListener();
214 info.setWorker();
215 info.setThreadId(currentThreadId++);
216 recursorThread();
217
218 handlerInfo.thread.join();
219 if (handlerInfo.exitCode != 0) {
220 ret = handlerInfo.exitCode;
221 }
222 taskInfo.thread.join();
223 if (taskInfo.exitCode != 0) {
224 ret = taskInfo.exitCode;
225 }
226 }
227 else {
228 // Setup RecThreadInfo objects
229 unsigned int tmp = currentThreadId;
230 if (RecThreadInfo::weDistributeQueries()) {
231 for (unsigned int n = 0; n < RecThreadInfo::numDistributors(); ++n) {
232 RecThreadInfo::info(tmp++).setListener();
233 }
234 }
235 for (unsigned int n = 0; n < RecThreadInfo::numWorkers(); ++n) {
236 auto& info = RecThreadInfo::info(tmp++);
237 info.setListener(!RecThreadInfo::weDistributeQueries());
238 info.setWorker();
239 }
240 for (unsigned int n = 0; n < RecThreadInfo::numTaskThreads(); ++n) {
241 auto& info = RecThreadInfo::info(tmp++);
242 info.setTaskThread();
243 }
244
245 // And now start the actual threads
246 if (RecThreadInfo::weDistributeQueries()) {
247 g_log << Logger::Warning << "Launching " << RecThreadInfo::numDistributors() << " distributor threads" << endl;
248 for (unsigned int n = 0; n < RecThreadInfo::numDistributors(); ++n) {
249 auto& info = RecThreadInfo::info(currentThreadId);
250 info.start(currentThreadId++, "distr", cpusMap);
251 }
252 }
253
254 g_log << Logger::Warning << "Launching " << RecThreadInfo::numWorkers() << " worker threads" << endl;
255
256 for (unsigned int n = 0; n < RecThreadInfo::numWorkers(); ++n) {
257 auto& info = RecThreadInfo::info(currentThreadId);
258 info.start(currentThreadId++, "worker", cpusMap);
259 }
260
261 for (unsigned int n = 0; n < RecThreadInfo::numTaskThreads(); ++n) {
262 auto& info = RecThreadInfo::info(currentThreadId);
263 info.start(currentThreadId++, "taskThread", cpusMap);
264 }
265
266 #ifdef HAVE_SYSTEMD
267 sd_notify(0, "READY=1");
268 #endif
269
270 /* This thread handles the web server, carbon, statistics and the control channel */
271 auto& info = RecThreadInfo::info(0);
272 info.setHandler();
273 info.start(0, "web+stat", cpusMap);
274
275 for (auto& ti : RecThreadInfo::infos()) {
276 ti.thread.join();
277 if (ti.exitCode != 0) {
278 ret = ti.exitCode;
279 }
280 }
281 }
282 return ret;
283 }
284
285 void RecThreadInfo::makeThreadPipes()
286 {
287 auto pipeBufferSize = ::arg().asNum("distribution-pipe-buffer-size");
288 if (pipeBufferSize > 0) {
289 g_log << Logger::Info << "Resizing the buffer of the distribution pipe to " << pipeBufferSize << endl;
290 }
291
292 /* thread 0 is the handler / SNMP, worker threads start at 1 */
293 for (unsigned int n = 0; n < numRecursorThreads(); ++n) {
294 auto& threadInfo = info(n);
295
296 int fd[2];
297 if (pipe(fd) < 0)
298 unixDie("Creating pipe for inter-thread communications");
299
300 threadInfo.pipes.readToThread = fd[0];
301 threadInfo.pipes.writeToThread = fd[1];
302
303 // handler thread only gets first pipe, not the others
304 if (n == 0) {
305 continue;
306 }
307
308 if (pipe(fd) < 0)
309 unixDie("Creating pipe for inter-thread communications");
310
311 threadInfo.pipes.readFromThread = fd[0];
312 threadInfo.pipes.writeFromThread = fd[1];
313
314 if (pipe(fd) < 0)
315 unixDie("Creating pipe for inter-thread communications");
316
317 threadInfo.pipes.readQueriesToThread = fd[0];
318 threadInfo.pipes.writeQueriesToThread = fd[1];
319
320 if (pipeBufferSize > 0) {
321 if (!setPipeBufferSize(threadInfo.pipes.writeQueriesToThread, pipeBufferSize)) {
322 int err = errno;
323 g_log << Logger::Warning << "Error resizing the buffer of the distribution pipe for thread " << n << " to " << pipeBufferSize << ": " << strerror(err) << endl;
324 auto existingSize = getPipeBufferSize(threadInfo.pipes.writeQueriesToThread);
325 if (existingSize > 0) {
326 g_log << Logger::Warning << "The current size of the distribution pipe's buffer for thread " << n << " is " << existingSize << endl;
327 }
328 }
329 }
330
331 if (!setNonBlocking(threadInfo.pipes.writeQueriesToThread)) {
332 unixDie("Making pipe for inter-thread communications non-blocking");
333 }
334 }
335 }
336
337 ArgvMap& arg()
338 {
339 static ArgvMap theArg;
340 return theArg;
341 }
342
343 static FDMultiplexer* getMultiplexer()
344 {
345 FDMultiplexer* ret;
346 for (const auto& i : FDMultiplexer::getMultiplexerMap()) {
347 try {
348 ret = i.second();
349 return ret;
350 }
351 catch (FDMultiplexerException& fe) {
352 g_log << Logger::Error << "Non-fatal error initializing possible multiplexer (" << fe.what() << "), falling back" << endl;
353 }
354 catch (...) {
355 g_log << Logger::Error << "Non-fatal error initializing possible multiplexer" << endl;
356 }
357 }
358 g_log << Logger::Error << "No working multiplexer found!" << endl;
359 _exit(1);
360 }
361
362 static std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>> startProtobufServers(const ProtobufExportConfig& config)
363 {
364 auto result = std::make_shared<std::vector<std::unique_ptr<RemoteLogger>>>();
365
366 for (const auto& server : config.servers) {
367 try {
368 auto logger = make_unique<RemoteLogger>(server, config.timeout, 100 * config.maxQueuedEntries, config.reconnectWaitTime, config.asyncConnect);
369 logger->setLogQueries(config.logQueries);
370 logger->setLogResponses(config.logResponses);
371 result->emplace_back(std::move(logger));
372 }
373 catch (const std::exception& e) {
374 g_log << Logger::Error << "Error while starting protobuf logger to '" << server << ": " << e.what() << endl;
375 }
376 catch (const PDNSException& e) {
377 g_log << Logger::Error << "Error while starting protobuf logger to '" << server << ": " << e.reason << endl;
378 }
379 }
380
381 return result;
382 }
383
384 bool checkProtobufExport(LocalStateHolder<LuaConfigItems>& luaconfsLocal)
385 {
386 if (!luaconfsLocal->protobufExportConfig.enabled) {
387 if (t_protobufServers) {
388 for (auto& server : *t_protobufServers) {
389 server->stop();
390 }
391 t_protobufServers.reset();
392 }
393
394 return false;
395 }
396
397 /* if the server was not running, or if it was running according to a
398 previous configuration */
399 if (!t_protobufServers || t_protobufServersGeneration < luaconfsLocal->generation) {
400
401 if (t_protobufServers) {
402 for (auto& server : *t_protobufServers) {
403 server->stop();
404 }
405 }
406 t_protobufServers.reset();
407
408 t_protobufServers = startProtobufServers(luaconfsLocal->protobufExportConfig);
409 t_protobufServersGeneration = luaconfsLocal->generation;
410 }
411
412 return true;
413 }
414
415 bool checkOutgoingProtobufExport(LocalStateHolder<LuaConfigItems>& luaconfsLocal)
416 {
417 if (!luaconfsLocal->outgoingProtobufExportConfig.enabled) {
418 if (t_outgoingProtobufServers) {
419 for (auto& server : *t_outgoingProtobufServers) {
420 server->stop();
421 }
422 }
423 t_outgoingProtobufServers.reset();
424
425 return false;
426 }
427
428 /* if the server was not running, or if it was running according to a
429 previous configuration */
430 if (!t_outgoingProtobufServers || t_outgoingProtobufServersGeneration < luaconfsLocal->generation) {
431
432 if (t_outgoingProtobufServers) {
433 for (auto& server : *t_outgoingProtobufServers) {
434 server->stop();
435 }
436 }
437 t_outgoingProtobufServers.reset();
438
439 t_outgoingProtobufServers = startProtobufServers(luaconfsLocal->outgoingProtobufExportConfig);
440 t_outgoingProtobufServersGeneration = luaconfsLocal->generation;
441 }
442
443 return true;
444 }
445
446 void protobufLogQuery(LocalStateHolder<LuaConfigItems>& luaconfsLocal, 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::unordered_set<std::string>& policyTags, const std::string& requestorId, const std::string& deviceId, const std::string& deviceName, const std::map<std::string, RecursorLua4::MetaValue>& meta)
447 {
448 if (!t_protobufServers) {
449 return;
450 }
451
452 Netmask requestorNM(remote, remote.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
453 ComboAddress requestor = requestorNM.getMaskedNetwork();
454 requestor.setPort(remote.getPort());
455
456 pdns::ProtoZero::RecMessage m{128, std::string::size_type(policyTags.empty() ? 0 : 64)}; // It's a guess
457 m.setType(pdns::ProtoZero::Message::MessageType::DNSQueryType);
458 m.setRequest(uniqueId, requestor, local, qname, qtype, qclass, id, tcp ? pdns::ProtoZero::Message::TransportProtocol::TCP : pdns::ProtoZero::Message::TransportProtocol::UDP, len);
459 m.setServerIdentity(SyncRes::s_serverID);
460 m.setEDNSSubnet(ednssubnet, ednssubnet.isIPv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
461 m.setRequestorId(requestorId);
462 m.setDeviceId(deviceId);
463 m.setDeviceName(deviceName);
464
465 if (!policyTags.empty()) {
466 m.addPolicyTags(policyTags);
467 }
468 for (const auto& mit : meta) {
469 m.setMeta(mit.first, mit.second.stringVal, mit.second.intVal);
470 }
471
472 std::string msg(m.finishAndMoveBuf());
473 for (auto& server : *t_protobufServers) {
474 server->queueData(msg);
475 }
476 }
477
478 void protobufLogResponse(pdns::ProtoZero::RecMessage& message)
479 {
480 if (!t_protobufServers) {
481 return;
482 }
483
484 std::string msg(message.finishAndMoveBuf());
485 for (auto& server : *t_protobufServers) {
486 server->queueData(msg);
487 }
488 }
489
490 void protobufLogResponse(const struct dnsheader* dh, LocalStateHolder<LuaConfigItems>& luaconfsLocal,
491 const RecursorPacketCache::OptPBData& pbData, const struct timeval& tv,
492 bool tcp, const ComboAddress& source, const ComboAddress& destination,
493 const EDNSSubnetOpts& ednssubnet,
494 const boost::uuids::uuid& uniqueId, const string& requestorId, const string& deviceId,
495 const string& deviceName, const std::map<std::string, RecursorLua4::MetaValue>& meta,
496 const RecEventTrace& eventTrace)
497 {
498 pdns::ProtoZero::RecMessage pbMessage(pbData ? pbData->d_message : "", pbData ? pbData->d_response : "", 64, 10); // The extra bytes we are going to add
499 // Normally we take the immutable string from the cache and append a few values, but if it's not there (can this happen?)
500 // we start with an empty string and append the minimal
501 if (!pbData) {
502 pbMessage.setType(pdns::ProtoZero::Message::MessageType::DNSResponseType);
503 pbMessage.setServerIdentity(SyncRes::s_serverID);
504 }
505
506 // In response part
507 if (g_useKernelTimestamp && tv.tv_sec) {
508 pbMessage.setQueryTime(tv.tv_sec, tv.tv_usec);
509 }
510 else {
511 pbMessage.setQueryTime(g_now.tv_sec, g_now.tv_usec);
512 }
513
514 // In message part
515 Netmask requestorNM(source, source.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
516 ComboAddress requestor = requestorNM.getMaskedNetwork();
517 pbMessage.setMessageIdentity(uniqueId);
518 pbMessage.setFrom(requestor);
519 pbMessage.setTo(destination);
520 pbMessage.setSocketProtocol(tcp ? pdns::ProtoZero::Message::TransportProtocol::TCP : pdns::ProtoZero::Message::TransportProtocol::UDP);
521 pbMessage.setId(dh->id);
522
523 pbMessage.setTime();
524 pbMessage.setEDNSSubnet(ednssubnet.source, ednssubnet.source.isIPv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
525 pbMessage.setRequestorId(requestorId);
526 pbMessage.setDeviceId(deviceId);
527 pbMessage.setDeviceName(deviceName);
528 pbMessage.setFromPort(source.getPort());
529 pbMessage.setToPort(destination.getPort());
530 for (const auto& m : meta) {
531 pbMessage.setMeta(m.first, m.second.stringVal, m.second.intVal);
532 }
533 #ifdef NOD_ENABLED
534 if (g_nodEnabled) {
535 pbMessage.setNewlyObservedDomain(false);
536 }
537 #endif
538 if (eventTrace.enabled() && SyncRes::s_event_trace_enabled & SyncRes::event_trace_to_pb) {
539 pbMessage.addEvents(eventTrace);
540 }
541 protobufLogResponse(pbMessage);
542 }
543
544 #ifdef HAVE_FSTRM
545
546 static std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>> startFrameStreamServers(const FrameStreamExportConfig& config)
547 {
548 auto result = std::make_shared<std::vector<std::unique_ptr<FrameStreamLogger>>>();
549
550 for (const auto& server : config.servers) {
551 try {
552 std::unordered_map<string, unsigned> options;
553 options["bufferHint"] = config.bufferHint;
554 options["flushTimeout"] = config.flushTimeout;
555 options["inputQueueSize"] = config.inputQueueSize;
556 options["outputQueueSize"] = config.outputQueueSize;
557 options["queueNotifyThreshold"] = config.queueNotifyThreshold;
558 options["reopenInterval"] = config.reopenInterval;
559 FrameStreamLogger* fsl = nullptr;
560 try {
561 ComboAddress address(server);
562 fsl = new FrameStreamLogger(address.sin4.sin_family, address.toStringWithPort(), true, options);
563 }
564 catch (const PDNSException& e) {
565 fsl = new FrameStreamLogger(AF_UNIX, server, true, options);
566 }
567 fsl->setLogQueries(config.logQueries);
568 fsl->setLogResponses(config.logResponses);
569 result->emplace_back(fsl);
570 }
571 catch (const std::exception& e) {
572 g_log << Logger::Error << "Error while starting dnstap framestream logger to '" << server << ": " << e.what() << endl;
573 }
574 catch (const PDNSException& e) {
575 g_log << Logger::Error << "Error while starting dnstap framestream logger to '" << server << ": " << e.reason << endl;
576 }
577 }
578
579 return result;
580 }
581
582 bool checkFrameStreamExport(LocalStateHolder<LuaConfigItems>& luaconfsLocal)
583 {
584 if (!luaconfsLocal->frameStreamExportConfig.enabled) {
585 if (t_frameStreamServers) {
586 // dt's take care of cleanup
587 t_frameStreamServers.reset();
588 }
589
590 return false;
591 }
592
593 /* if the server was not running, or if it was running according to a
594 previous configuration */
595 if (!t_frameStreamServers || t_frameStreamServersGeneration < luaconfsLocal->generation) {
596
597 if (t_frameStreamServers) {
598 // dt's take care of cleanup
599 t_frameStreamServers.reset();
600 }
601
602 t_frameStreamServers = startFrameStreamServers(luaconfsLocal->frameStreamExportConfig);
603 t_frameStreamServersGeneration = luaconfsLocal->generation;
604 }
605
606 return true;
607 }
608 #endif /* HAVE_FSTRM */
609
610 static void makeControlChannelSocket(int processNum = -1)
611 {
612 string sockname = ::arg()["socket-dir"] + "/" + g_programname;
613 if (processNum >= 0)
614 sockname += "." + std::to_string(processNum);
615 sockname += ".controlsocket";
616 g_rcc.listen(sockname);
617
618 int sockowner = -1;
619 int sockgroup = -1;
620
621 if (!::arg().isEmpty("socket-group"))
622 sockgroup = ::arg().asGid("socket-group");
623 if (!::arg().isEmpty("socket-owner"))
624 sockowner = ::arg().asUid("socket-owner");
625
626 if (sockgroup > -1 || sockowner > -1) {
627 if (chown(sockname.c_str(), sockowner, sockgroup) < 0) {
628 unixDie("Failed to chown control socket");
629 }
630 }
631
632 // do mode change if socket-mode is given
633 if (!::arg().isEmpty("socket-mode")) {
634 mode_t sockmode = ::arg().asMode("socket-mode");
635 if (chmod(sockname.c_str(), sockmode) < 0) {
636 unixDie("Failed to chmod control socket");
637 }
638 }
639 }
640
641 static void writePid(void)
642 {
643 if (!::arg().mustDo("write-pid"))
644 return;
645 ofstream of(g_pidfname.c_str(), std::ios_base::app);
646 if (of)
647 of << Utility::getpid() << endl;
648 else {
649 int err = errno;
650 g_log << Logger::Error << "Writing pid for " << Utility::getpid() << " to " << g_pidfname << " failed: "
651 << stringerror(err) << endl;
652 }
653 }
654
655 static void checkSocketDir(void)
656 {
657 struct stat st;
658 string dir(::arg()["socket-dir"]);
659 string msg;
660
661 if (stat(dir.c_str(), &st) == -1) {
662 msg = "it does not exist or cannot access";
663 }
664 else if (!S_ISDIR(st.st_mode)) {
665 msg = "it is not a directory";
666 }
667 else if (access(dir.c_str(), R_OK | W_OK | X_OK) != 0) {
668 msg = "cannot read, write or search";
669 }
670 else {
671 return;
672 }
673 g_log << Logger::Error << "Problem with socket directory " << dir << ": " << msg << "; see https://docs.powerdns.com/recursor/upgrade.html#x-to-4-3-0" << endl;
674 _exit(1);
675 }
676
677 #ifdef NOD_ENABLED
678 static void setupNODThread()
679 {
680 if (g_nodEnabled) {
681 uint32_t num_cells = ::arg().asNum("new-domain-db-size");
682 t_nodDBp = std::make_shared<nod::NODDB>(num_cells);
683 try {
684 t_nodDBp->setCacheDir(::arg()["new-domain-history-dir"]);
685 }
686 catch (const PDNSException& e) {
687 g_log << Logger::Error << "new-domain-history-dir (" << ::arg()["new-domain-history-dir"] << ") is not readable or does not exist" << endl;
688 _exit(1);
689 }
690 if (!t_nodDBp->init()) {
691 g_log << Logger::Error << "Could not initialize domain tracking" << endl;
692 _exit(1);
693 }
694 std::thread t(nod::NODDB::startHousekeepingThread, t_nodDBp, std::this_thread::get_id());
695 t.detach();
696 g_nod_pbtag = ::arg()["new-domain-pb-tag"];
697 }
698 if (g_udrEnabled) {
699 uint32_t num_cells = ::arg().asNum("unique-response-db-size");
700 t_udrDBp = std::make_shared<nod::UniqueResponseDB>(num_cells);
701 try {
702 t_udrDBp->setCacheDir(::arg()["unique-response-history-dir"]);
703 }
704 catch (const PDNSException& e) {
705 g_log << Logger::Error << "unique-response-history-dir (" << ::arg()["unique-response-history-dir"] << ") is not readable or does not exist" << endl;
706 _exit(1);
707 }
708 if (!t_udrDBp->init()) {
709 g_log << Logger::Error << "Could not initialize unique response tracking" << endl;
710 _exit(1);
711 }
712 std::thread t(nod::UniqueResponseDB::startHousekeepingThread, t_udrDBp, std::this_thread::get_id());
713 t.detach();
714 g_udr_pbtag = ::arg()["unique-response-pb-tag"];
715 }
716 }
717
718 static void parseNODIgnorelist(const std::string& wlist)
719 {
720 vector<string> parts;
721 stringtok(parts, wlist, ",; ");
722 for (const auto& a : parts) {
723 g_nodDomainWL.add(DNSName(a));
724 }
725 }
726
727 static void setupNODGlobal()
728 {
729 // Setup NOD subsystem
730 g_nodEnabled = ::arg().mustDo("new-domain-tracking");
731 g_nodLookupDomain = DNSName(::arg()["new-domain-lookup"]);
732 g_nodLog = ::arg().mustDo("new-domain-log");
733 parseNODIgnorelist(::arg()["new-domain-whitelist"]);
734 parseNODIgnorelist(::arg()["new-domain-ignore-list"]);
735
736 // Setup Unique DNS Response subsystem
737 g_udrEnabled = ::arg().mustDo("unique-response-tracking");
738 g_udrLog = ::arg().mustDo("unique-response-log");
739 }
740 #endif /* NOD_ENABLED */
741
742 static void daemonize(void)
743 {
744 if (fork())
745 exit(0); // bye bye
746
747 setsid();
748
749 int i = open("/dev/null", O_RDWR); /* open stdin */
750 if (i < 0)
751 g_log << Logger::Critical << "Unable to open /dev/null: " << stringerror() << endl;
752 else {
753 dup2(i, 0); /* stdin */
754 dup2(i, 1); /* stderr */
755 dup2(i, 2); /* stderr */
756 close(i);
757 }
758 }
759
760 static void termIntHandler(int)
761 {
762 doExit();
763 }
764
765 static void usr1Handler(int)
766 {
767 statsWanted = true;
768 }
769
770 static void usr2Handler(int)
771 {
772 g_quiet = !g_quiet;
773 SyncRes::setDefaultLogMode(g_quiet ? SyncRes::LogNone : SyncRes::Log);
774 ::arg().set("quiet") = g_quiet ? "" : "no";
775 }
776
777 static void checkLinuxIPv6Limits()
778 {
779 #ifdef __linux__
780 string line;
781 if (readFileIfThere("/proc/sys/net/ipv6/route/max_size", &line)) {
782 int lim = std::stoi(line);
783 if (lim < 16384) {
784 g_log << Logger::Error << "If using IPv6, please raise sysctl net.ipv6.route.max_size, currently set to " << lim << " which is < 16384" << endl;
785 }
786 }
787 #endif
788 }
789
790 static void checkOrFixFDS()
791 {
792 unsigned int availFDs = getFilenumLimit();
793 unsigned int wantFDs = g_maxMThreads * RecThreadInfo::numWorkers() + 25; // even healthier margin then before
794 wantFDs += RecThreadInfo::numWorkers() * TCPOutConnectionManager::s_maxIdlePerThread;
795
796 if (wantFDs > availFDs) {
797 unsigned int hardlimit = getFilenumLimit(true);
798 if (hardlimit >= wantFDs) {
799 setFilenumLimit(wantFDs);
800 g_log << Logger::Warning << "Raised soft limit on number of filedescriptors to " << wantFDs << " to match max-mthreads and threads settings" << endl;
801 }
802 else {
803 int newval = (hardlimit - 25 - TCPOutConnectionManager::s_maxIdlePerThread) / RecThreadInfo::numWorkers();
804 g_log << Logger::Warning << "Insufficient number of filedescriptors available for max-mthreads*threads setting! (" << hardlimit << " < " << wantFDs << "), reducing max-mthreads to " << newval << endl;
805 g_maxMThreads = newval;
806 setFilenumLimit(hardlimit);
807 }
808 }
809 }
810
811 // static std::string s_timestampFormat = "%m-%dT%H:%M:%S";
812 static std::string s_timestampFormat = "%s";
813
814 static const char* toTimestampStringMilli(const struct timeval& tv, char* buf, size_t sz)
815 {
816 struct tm tm;
817 size_t len = strftime(buf, sz, s_timestampFormat.c_str(), localtime_r(&tv.tv_sec, &tm));
818 if (len == 0) {
819 len = snprintf(buf, sz, "%lld", static_cast<long long>(tv.tv_sec));
820 }
821
822 snprintf(buf + len, sz - len, ".%03ld", static_cast<long>(tv.tv_usec) / 1000);
823 return buf;
824 }
825
826 static void loggerBackend(const Logging::Entry& entry)
827 {
828 static thread_local std::stringstream buf;
829
830 buf.str("");
831 buf << "msg=" << std::quoted(entry.message);
832 if (entry.error) {
833 buf << " oserror=" << std::quoted(entry.error.get());
834 }
835
836 if (entry.name) {
837 buf << " subsystem=" << std::quoted(entry.name.get());
838 }
839 buf << " level=" << entry.level;
840 if (entry.d_priority) {
841 buf << " prio=" << static_cast<int>(entry.d_priority);
842 }
843 char timebuf[64];
844 buf << " ts=" << std::quoted(toTimestampStringMilli(entry.d_timestamp, timebuf, sizeof(timebuf)));
845 for (auto const& v : entry.values) {
846 buf << " ";
847 buf << v.first << "=" << std::quoted(v.second);
848 }
849 Logger::Urgency u = entry.d_priority ? Logger::Urgency(entry.d_priority) : Logger::Info;
850 g_log << u << buf.str() << endl;
851 }
852
853 static int ratePercentage(uint64_t nom, uint64_t denom)
854 {
855 if (denom == 0) {
856 return 0;
857 }
858 return round(100.0 * nom / denom);
859 }
860
861 static void doStats(void)
862 {
863 static time_t lastOutputTime;
864 static uint64_t lastQueryCount;
865
866 uint64_t cacheHits = g_recCache->cacheHits;
867 uint64_t cacheMisses = g_recCache->cacheMisses;
868 uint64_t cacheSize = g_recCache->size();
869 auto rc_stats = g_recCache->stats();
870 double r = rc_stats.second == 0 ? 0.0 : (100.0 * rc_stats.first / rc_stats.second);
871 uint64_t negCacheSize = g_negCache->size();
872 auto taskPushes = getTaskPushes();
873 auto taskExpired = getTaskExpired();
874 auto taskSize = getTaskSize();
875
876 if (g_stats.qcounter && (cacheHits + cacheMisses) && SyncRes::s_queries && SyncRes::s_outqueries) {
877 g_log << Logger::Notice << "stats: " << g_stats.qcounter << " questions, " << cacheSize << " cache entries, " << negCacheSize << " negative entries, " << ratePercentage(cacheHits, cacheHits + cacheMisses) << "% cache hits" << endl;
878 g_log << Logger::Notice << "stats: cache contended/acquired " << rc_stats.first << '/' << rc_stats.second << " = " << r << '%' << endl;
879
880 g_log << Logger::Notice << "stats: throttle map: "
881 << broadcastAccFunction<uint64_t>(pleaseGetThrottleSize) << ", ns speeds: "
882 << broadcastAccFunction<uint64_t>(pleaseGetNsSpeedsSize) << ", failed ns: "
883 << SyncRes::getFailedServersSize() << ", ednsmap: "
884 << broadcastAccFunction<uint64_t>(pleaseGetEDNSStatusesSize) << endl;
885 g_log << Logger::Notice << "stats: outpacket/query ratio " << ratePercentage(SyncRes::s_outqueries, SyncRes::s_queries) << "%";
886 g_log << Logger::Notice << ", " << ratePercentage(SyncRes::s_throttledqueries, SyncRes::s_outqueries + SyncRes::s_throttledqueries) << "% throttled" << endl;
887 g_log << Logger::Notice << "stats: " << SyncRes::s_tcpoutqueries << "/" << SyncRes::s_dotoutqueries << "/" << getCurrentIdleTCPConnections() << " outgoing tcp/dot/idle connections, " << broadcastAccFunction<uint64_t>(pleaseGetConcurrentQueries) << " queries running, " << SyncRes::s_outgoingtimeouts << " outgoing timeouts " << endl;
888
889 uint64_t pcSize = broadcastAccFunction<uint64_t>(pleaseGetPacketCacheSize);
890 uint64_t pcHits = broadcastAccFunction<uint64_t>(pleaseGetPacketCacheHits);
891 g_log << Logger::Notice << "stats: " << pcSize << " packet cache entries, " << ratePercentage(pcHits, SyncRes::s_queries) << "% packet cache hits" << endl;
892
893 size_t idx = 0;
894 for (const auto& threadInfo : RecThreadInfo::infos()) {
895 if (threadInfo.isWorker()) {
896 g_log << Logger::Notice << "stats: thread " << idx << " has been distributed " << threadInfo.numberOfDistributedQueries << " queries" << endl;
897 ++idx;
898 }
899 }
900
901 g_log << Logger::Notice << "stats: tasks pushed/expired/queuesize: " << taskPushes << '/' << taskExpired << '/' << taskSize << endl;
902 time_t now = time(0);
903 if (lastOutputTime && lastQueryCount && now != lastOutputTime) {
904 g_log << Logger::Notice << "stats: " << (SyncRes::s_queries - lastQueryCount) / (now - lastOutputTime) << " qps (average over " << (now - lastOutputTime) << " seconds)" << endl;
905 }
906 lastOutputTime = now;
907 lastQueryCount = SyncRes::s_queries;
908 }
909 else if (statsWanted)
910 g_log << Logger::Notice << "stats: no stats yet!" << endl;
911
912 statsWanted = false;
913 }
914
915 static std::shared_ptr<NetmaskGroup> parseACL(const std::string& aclFile, const std::string& aclSetting)
916 {
917 auto result = std::make_shared<NetmaskGroup>();
918
919 if (!::arg()[aclFile].empty()) {
920 string line;
921 ifstream ifs(::arg()[aclFile].c_str());
922 if (!ifs) {
923 throw runtime_error("Could not open '" + ::arg()[aclFile] + "': " + stringerror());
924 }
925
926 string::size_type pos;
927 while (getline(ifs, line)) {
928 pos = line.find('#');
929 if (pos != string::npos)
930 line.resize(pos);
931 boost::trim(line);
932 if (line.empty())
933 continue;
934
935 result->addMask(line);
936 }
937 g_log << Logger::Info << "Done parsing " << result->size() << " " << aclSetting << " ranges from file '" << ::arg()[aclFile] << "' - overriding '" << aclSetting << "' setting" << endl;
938
939 return result;
940 }
941 else if (!::arg()[aclSetting].empty()) {
942 vector<string> ips;
943 stringtok(ips, ::arg()[aclSetting], ", ");
944
945 g_log << Logger::Info << aclSetting << ": ";
946 for (vector<string>::const_iterator i = ips.begin(); i != ips.end(); ++i) {
947 result->addMask(*i);
948 if (i != ips.begin())
949 g_log << Logger::Info << ", ";
950 g_log << Logger::Info << *i;
951 }
952 g_log << Logger::Info << endl;
953
954 return result;
955 }
956
957 return nullptr;
958 }
959
960 static void* pleaseSupplantAllowFrom(std::shared_ptr<NetmaskGroup> ng)
961 {
962 t_allowFrom = ng;
963 return nullptr;
964 }
965
966 static void* pleaseSupplantAllowNotifyFrom(std::shared_ptr<NetmaskGroup> ng)
967 {
968 t_allowNotifyFrom = ng;
969 return nullptr;
970 }
971
972 void* pleaseSupplantAllowNotifyFor(std::shared_ptr<notifyset_t> ns)
973 {
974 t_allowNotifyFor = ns;
975 return nullptr;
976 }
977
978 void parseACLs()
979 {
980 static bool l_initialized;
981
982 if (l_initialized) { // only reload configuration file on second call
983 string configname = ::arg()["config-dir"] + "/recursor.conf";
984 if (::arg()["config-name"] != "") {
985 configname = ::arg()["config-dir"] + "/recursor-" + ::arg()["config-name"] + ".conf";
986 }
987 cleanSlashes(configname);
988
989 if (!::arg().preParseFile(configname.c_str(), "allow-from-file"))
990 throw runtime_error("Unable to re-parse configuration file '" + configname + "'");
991 ::arg().preParseFile(configname.c_str(), "allow-from", LOCAL_NETS);
992
993 if (!::arg().preParseFile(configname.c_str(), "allow-notify-from-file"))
994 throw runtime_error("Unable to re-parse configuration file '" + configname + "'");
995 ::arg().preParseFile(configname.c_str(), "allow-notify-from");
996
997 ::arg().preParseFile(configname.c_str(), "include-dir");
998 ::arg().preParse(g_argc, g_argv, "include-dir");
999
1000 // then process includes
1001 std::vector<std::string> extraConfigs;
1002 ::arg().gatherIncludes(extraConfigs);
1003
1004 for (const std::string& fn : extraConfigs) {
1005 if (!::arg().preParseFile(fn.c_str(), "allow-from-file", ::arg()["allow-from-file"]))
1006 throw runtime_error("Unable to re-parse configuration file include '" + fn + "'");
1007 if (!::arg().preParseFile(fn.c_str(), "allow-from", ::arg()["allow-from"]))
1008 throw runtime_error("Unable to re-parse configuration file include '" + fn + "'");
1009
1010 if (!::arg().preParseFile(fn.c_str(), "allow-notify-from-file", ::arg()["allow-notify-from-file"]))
1011 throw runtime_error("Unable to re-parse configuration file include '" + fn + "'");
1012 if (!::arg().preParseFile(fn.c_str(), "allow-notify-from", ::arg()["allow-notify-from"]))
1013 throw runtime_error("Unable to re-parse configuration file include '" + fn + "'");
1014 }
1015
1016 ::arg().preParse(g_argc, g_argv, "allow-from-file");
1017 ::arg().preParse(g_argc, g_argv, "allow-from");
1018
1019 ::arg().preParse(g_argc, g_argv, "allow-notify-from-file");
1020 ::arg().preParse(g_argc, g_argv, "allow-notify-from");
1021 }
1022
1023 auto allowFrom = parseACL("allow-from-file", "allow-from");
1024
1025 if (allowFrom->size() == 0) {
1026 if (::arg()["local-address"] != "127.0.0.1" && ::arg().asNum("local-port") == 53)
1027 g_log << Logger::Warning << "WARNING: Allowing queries from all IP addresses - this can be a security risk!" << endl;
1028 allowFrom = nullptr;
1029 }
1030
1031 g_initialAllowFrom = allowFrom;
1032 broadcastFunction([=] { return pleaseSupplantAllowFrom(allowFrom); });
1033
1034 auto allowNotifyFrom = parseACL("allow-notify-from-file", "allow-notify-from");
1035
1036 g_initialAllowNotifyFrom = allowNotifyFrom;
1037 broadcastFunction([=] { return pleaseSupplantAllowNotifyFrom(allowNotifyFrom); });
1038
1039 l_initialized = true;
1040 }
1041
1042 void broadcastFunction(const pipefunc_t& func)
1043 {
1044 /* This function might be called by the worker with t_id 0 during startup
1045 for the initialization of ACLs and domain maps. After that it should only
1046 be called by the handler. */
1047
1048 if (RecThreadInfo::infos().empty() && RecThreadInfo::id() == 0) {
1049 /* the handler and distributors will call themselves below, but
1050 during startup we get called while g_threadInfos has not been
1051 populated yet to update the ACL or domain maps, so we need to
1052 handle that case.
1053 */
1054 func();
1055 }
1056
1057 unsigned int n = 0;
1058 for (const auto& threadInfo : RecThreadInfo::infos()) {
1059 if (n++ == RecThreadInfo::id()) {
1060 func(); // don't write to ourselves!
1061 continue;
1062 }
1063
1064 ThreadMSG* tmsg = new ThreadMSG();
1065 tmsg->func = func;
1066 tmsg->wantAnswer = true;
1067 if (write(threadInfo.pipes.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) {
1068 delete tmsg;
1069
1070 unixDie("write to thread pipe returned wrong size or error");
1071 }
1072
1073 string* resp = nullptr;
1074 if (read(threadInfo.pipes.readFromThread, &resp, sizeof(resp)) != sizeof(resp))
1075 unixDie("read from thread pipe returned wrong size or error");
1076
1077 if (resp) {
1078 delete resp;
1079 resp = nullptr;
1080 }
1081 }
1082 }
1083
1084 template <class T>
1085 void* voider(const boost::function<T*()>& func)
1086 {
1087 return func();
1088 }
1089
1090 static vector<ComboAddress>& operator+=(vector<ComboAddress>& a, const vector<ComboAddress>& b)
1091 {
1092 a.insert(a.end(), b.begin(), b.end());
1093 return a;
1094 }
1095
1096 static vector<pair<DNSName, uint16_t>>& operator+=(vector<pair<DNSName, uint16_t>>& a, const vector<pair<DNSName, uint16_t>>& b)
1097 {
1098 a.insert(a.end(), b.begin(), b.end());
1099 return a;
1100 }
1101
1102 // This function should only be called by the handler to gather
1103 // metrics, wipe the cache, reload the Lua script (not the Lua config)
1104 // or change the current trace regex, and by the SNMP thread to gather
1105 // metrics.
1106 // Note that this currently skips the handler, but includes the taskThread(s).
1107 template <class T>
1108 T broadcastAccFunction(const boost::function<T*()>& func)
1109 {
1110 if (!RecThreadInfo::self().isHandler()) {
1111 g_log << Logger::Error << "broadcastAccFunction has been called by a worker (" << RecThreadInfo::id() << ")" << endl;
1112 _exit(1);
1113 }
1114
1115 unsigned int n = 0;
1116 T ret = T();
1117 for (const auto& threadInfo : RecThreadInfo::infos()) {
1118 if (n++ == RecThreadInfo::id()) {
1119 continue;
1120 }
1121
1122 const auto& tps = threadInfo.pipes;
1123 ThreadMSG* tmsg = new ThreadMSG();
1124 tmsg->func = [func] { return voider<T>(func); };
1125 tmsg->wantAnswer = true;
1126
1127 if (write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) {
1128 delete tmsg;
1129 unixDie("write to thread pipe returned wrong size or error");
1130 }
1131
1132 T* resp = nullptr;
1133 if (read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp))
1134 unixDie("read from thread pipe returned wrong size or error");
1135
1136 if (resp) {
1137 ret += *resp;
1138 delete resp;
1139 resp = nullptr;
1140 }
1141 }
1142 return ret;
1143 }
1144
1145 template string broadcastAccFunction(const boost::function<string*()>& fun); // explicit instantiation
1146 template RecursorControlChannel::Answer broadcastAccFunction(const boost::function<RecursorControlChannel::Answer*()>& fun); // explicit instantiation
1147 template uint64_t broadcastAccFunction(const boost::function<uint64_t*()>& fun); // explicit instantiation
1148 template vector<ComboAddress> broadcastAccFunction(const boost::function<vector<ComboAddress>*()>& fun); // explicit instantiation
1149 template vector<pair<DNSName, uint16_t>> broadcastAccFunction(const boost::function<vector<pair<DNSName, uint16_t>>*()>& fun); // explicit instantiation
1150 template ThreadTimes broadcastAccFunction(const boost::function<ThreadTimes*()>& fun);
1151
1152 static int serviceMain(int argc, char* argv[])
1153 {
1154 g_slogStructured = ::arg().mustDo("structured-logging");
1155
1156 g_log.setName(g_programname);
1157 g_log.disableSyslog(::arg().mustDo("disable-syslog"));
1158 g_log.setTimestamps(::arg().mustDo("log-timestamp"));
1159
1160 if (!::arg()["logging-facility"].empty()) {
1161 int val = logFacilityToLOG(::arg().asNum("logging-facility"));
1162 if (val >= 0)
1163 g_log.setFacility(val);
1164 else
1165 g_log << Logger::Error << "Unknown logging facility " << ::arg().asNum("logging-facility") << endl;
1166 }
1167
1168 showProductVersion();
1169
1170 g_disthashseed = dns_random(0xffffffff);
1171
1172 checkLinuxIPv6Limits();
1173 try {
1174 pdns::parseQueryLocalAddress(::arg()["query-local-address"]);
1175 }
1176 catch (std::exception& e) {
1177 g_log << Logger::Error << "Assigning local query addresses: " << e.what();
1178 exit(99);
1179 }
1180
1181 if (pdns::isQueryLocalAddressFamilyEnabled(AF_INET)) {
1182 SyncRes::s_doIPv4 = true;
1183 g_log << Logger::Warning << "Enabling IPv4 transport for outgoing queries" << endl;
1184 }
1185 else {
1186 g_log << Logger::Warning << "NOT using IPv4 for outgoing queries - add an IPv4 address (like '0.0.0.0') to query-local-address to enable" << endl;
1187 }
1188
1189 if (pdns::isQueryLocalAddressFamilyEnabled(AF_INET6)) {
1190 SyncRes::s_doIPv6 = true;
1191 g_log << Logger::Warning << "Enabling IPv6 transport for outgoing queries" << endl;
1192 }
1193 else {
1194 g_log << Logger::Warning << "NOT using IPv6 for outgoing queries - add an IPv6 address (like '::') to query-local-address to enable" << endl;
1195 }
1196
1197 if (!SyncRes::s_doIPv6 && !SyncRes::s_doIPv4) {
1198 g_log << Logger::Error << "No outgoing addresses configured! Can not continue" << endl;
1199 exit(99);
1200 }
1201
1202 // keep this ABOVE loadRecursorLuaConfig!
1203 if (::arg()["dnssec"] == "off")
1204 g_dnssecmode = DNSSECMode::Off;
1205 else if (::arg()["dnssec"] == "process-no-validate")
1206 g_dnssecmode = DNSSECMode::ProcessNoValidate;
1207 else if (::arg()["dnssec"] == "process")
1208 g_dnssecmode = DNSSECMode::Process;
1209 else if (::arg()["dnssec"] == "validate")
1210 g_dnssecmode = DNSSECMode::ValidateAll;
1211 else if (::arg()["dnssec"] == "log-fail")
1212 g_dnssecmode = DNSSECMode::ValidateForLog;
1213 else {
1214 g_log << Logger::Error << "Unknown DNSSEC mode " << ::arg()["dnssec"] << endl;
1215 exit(1);
1216 }
1217
1218 g_signatureInceptionSkew = ::arg().asNum("signature-inception-skew");
1219 if (g_signatureInceptionSkew < 0) {
1220 g_log << Logger::Error << "A negative value for 'signature-inception-skew' is not allowed" << endl;
1221 exit(1);
1222 }
1223
1224 g_dnssecLogBogus = ::arg().mustDo("dnssec-log-bogus");
1225 g_maxNSEC3Iterations = ::arg().asNum("nsec3-max-iterations");
1226
1227 g_maxCacheEntries = ::arg().asNum("max-cache-entries");
1228 g_maxPacketCacheEntries = ::arg().asNum("max-packetcache-entries");
1229
1230 luaConfigDelayedThreads delayedLuaThreads;
1231 try {
1232 loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads);
1233 }
1234 catch (PDNSException& e) {
1235 g_log << Logger::Error << "Cannot load Lua configuration: " << e.reason << endl;
1236 exit(1);
1237 }
1238
1239 parseACLs();
1240 initPublicSuffixList(::arg()["public-suffix-list-file"]);
1241
1242 if (!::arg()["dont-query"].empty()) {
1243 vector<string> ips;
1244 stringtok(ips, ::arg()["dont-query"], ", ");
1245 ips.push_back("0.0.0.0");
1246 ips.push_back("::");
1247
1248 g_log << Logger::Warning << "Will not send queries to: ";
1249 for (vector<string>::const_iterator i = ips.begin(); i != ips.end(); ++i) {
1250 SyncRes::addDontQuery(*i);
1251 if (i != ips.begin())
1252 g_log << Logger::Warning << ", ";
1253 g_log << Logger::Warning << *i;
1254 }
1255 g_log << Logger::Warning << endl;
1256 }
1257
1258 /* this needs to be done before parseACLs(), which call broadcastFunction() */
1259 RecThreadInfo::setWeDistributeQueries(::arg().mustDo("pdns-distributes-queries"));
1260 if (RecThreadInfo::weDistributeQueries()) {
1261 g_log << Logger::Warning << "PowerDNS Recursor itself will distribute queries over threads" << endl;
1262 }
1263
1264 g_outgoingEDNSBufsize = ::arg().asNum("edns-outgoing-bufsize");
1265
1266 if (::arg()["trace"] == "fail") {
1267 SyncRes::setDefaultLogMode(SyncRes::Store);
1268 }
1269 else if (::arg().mustDo("trace")) {
1270 SyncRes::setDefaultLogMode(SyncRes::Log);
1271 ::arg().set("quiet") = "no";
1272 g_quiet = false;
1273 g_dnssecLOG = true;
1274 }
1275 string myHostname = getHostname();
1276 if (myHostname == "UNKNOWN") {
1277 g_log << Logger::Warning << "Unable to get the hostname, NSID and id.server values will be empty" << endl;
1278 myHostname = "";
1279 }
1280
1281 SyncRes::s_minimumTTL = ::arg().asNum("minimum-ttl-override");
1282 SyncRes::s_minimumECSTTL = ::arg().asNum("ecs-minimum-ttl-override");
1283
1284 SyncRes::s_nopacketcache = ::arg().mustDo("disable-packetcache");
1285
1286 SyncRes::s_maxnegttl = ::arg().asNum("max-negative-ttl");
1287 SyncRes::s_maxbogusttl = ::arg().asNum("max-cache-bogus-ttl");
1288 SyncRes::s_maxcachettl = max(::arg().asNum("max-cache-ttl"), 15);
1289 SyncRes::s_packetcachettl = ::arg().asNum("packetcache-ttl");
1290 // Cap the packetcache-servfail-ttl to the packetcache-ttl
1291 uint32_t packetCacheServFailTTL = ::arg().asNum("packetcache-servfail-ttl");
1292 SyncRes::s_packetcacheservfailttl = (packetCacheServFailTTL > SyncRes::s_packetcachettl) ? SyncRes::s_packetcachettl : packetCacheServFailTTL;
1293 SyncRes::s_serverdownmaxfails = ::arg().asNum("server-down-max-fails");
1294 SyncRes::s_serverdownthrottletime = ::arg().asNum("server-down-throttle-time");
1295 SyncRes::s_nonresolvingnsmaxfails = ::arg().asNum("non-resolving-ns-max-fails");
1296 SyncRes::s_nonresolvingnsthrottletime = ::arg().asNum("non-resolving-ns-throttle-time");
1297 SyncRes::s_serverID = ::arg()["server-id"];
1298 SyncRes::s_maxqperq = ::arg().asNum("max-qperq");
1299 SyncRes::s_maxnsaddressqperq = ::arg().asNum("max-ns-address-qperq");
1300 SyncRes::s_maxtotusec = 1000 * ::arg().asNum("max-total-msec");
1301 SyncRes::s_maxdepth = ::arg().asNum("max-recursion-depth");
1302 SyncRes::s_rootNXTrust = ::arg().mustDo("root-nx-trust");
1303 SyncRes::s_refresh_ttlperc = ::arg().asNum("refresh-on-ttl-perc");
1304 RecursorPacketCache::s_refresh_ttlperc = SyncRes::s_refresh_ttlperc;
1305 SyncRes::s_tcp_fast_open = ::arg().asNum("tcp-fast-open");
1306 SyncRes::s_tcp_fast_open_connect = ::arg().mustDo("tcp-fast-open-connect");
1307
1308 SyncRes::s_dot_to_port_853 = ::arg().mustDo("dot-to-port-853");
1309 SyncRes::s_event_trace_enabled = ::arg().asNum("event-trace-enabled");
1310
1311 if (SyncRes::s_tcp_fast_open_connect) {
1312 checkFastOpenSysctl(true);
1313 checkTFOconnect();
1314 }
1315
1316 if (SyncRes::s_serverID.empty()) {
1317 SyncRes::s_serverID = myHostname;
1318 }
1319
1320 SyncRes::s_ecsipv4limit = ::arg().asNum("ecs-ipv4-bits");
1321 SyncRes::s_ecsipv6limit = ::arg().asNum("ecs-ipv6-bits");
1322 SyncRes::clearECSStats();
1323 SyncRes::s_ecsipv4cachelimit = ::arg().asNum("ecs-ipv4-cache-bits");
1324 SyncRes::s_ecsipv6cachelimit = ::arg().asNum("ecs-ipv6-cache-bits");
1325 SyncRes::s_ecsipv4nevercache = ::arg().mustDo("ecs-ipv4-never-cache");
1326 SyncRes::s_ecsipv6nevercache = ::arg().mustDo("ecs-ipv6-never-cache");
1327 SyncRes::s_ecscachelimitttl = ::arg().asNum("ecs-cache-limit-ttl");
1328
1329 SyncRes::s_qnameminimization = ::arg().mustDo("qname-minimization");
1330
1331 if (SyncRes::s_qnameminimization) {
1332 // With an empty cache, a rev ipv6 query with dnssec enabled takes
1333 // almost 100 queries. Default maxqperq is 60.
1334 SyncRes::s_maxqperq = std::max(SyncRes::s_maxqperq, static_cast<unsigned int>(100));
1335 }
1336
1337 SyncRes::s_hardenNXD = SyncRes::HardenNXD::DNSSEC;
1338 string value = ::arg()["nothing-below-nxdomain"];
1339 if (value == "yes") {
1340 SyncRes::s_hardenNXD = SyncRes::HardenNXD::Yes;
1341 }
1342 else if (value == "no") {
1343 SyncRes::s_hardenNXD = SyncRes::HardenNXD::No;
1344 }
1345 else if (value != "dnssec") {
1346 g_log << Logger::Error << "Unknown nothing-below-nxdomain mode: " << value << endl;
1347 exit(1);
1348 }
1349
1350 if (!::arg().isEmpty("ecs-scope-zero-address")) {
1351 ComboAddress scopeZero(::arg()["ecs-scope-zero-address"]);
1352 SyncRes::setECSScopeZeroAddress(Netmask(scopeZero, scopeZero.isIPv4() ? 32 : 128));
1353 }
1354 else {
1355 Netmask nm;
1356 bool done = false;
1357
1358 auto addr = pdns::getNonAnyQueryLocalAddress(AF_INET);
1359 if (addr.sin4.sin_family != 0) {
1360 nm = Netmask(addr, 32);
1361 done = true;
1362 }
1363 if (!done) {
1364 addr = pdns::getNonAnyQueryLocalAddress(AF_INET6);
1365 if (addr.sin4.sin_family != 0) {
1366 nm = Netmask(addr, 128);
1367 done = true;
1368 }
1369 }
1370 if (!done) {
1371 nm = Netmask(ComboAddress("127.0.0.1"), 32);
1372 }
1373 SyncRes::setECSScopeZeroAddress(nm);
1374 }
1375
1376 SyncRes::parseEDNSSubnetAllowlist(::arg()["edns-subnet-whitelist"]);
1377 SyncRes::parseEDNSSubnetAllowlist(::arg()["edns-subnet-allow-list"]);
1378 SyncRes::parseEDNSSubnetAddFor(::arg()["ecs-add-for"]);
1379 g_useIncomingECS = ::arg().mustDo("use-incoming-edns-subnet");
1380
1381 g_XPFAcl.toMasks(::arg()["xpf-allow-from"]);
1382 g_xpfRRCode = ::arg().asNum("xpf-rr-code");
1383
1384 g_proxyProtocolACL.toMasks(::arg()["proxy-protocol-from"]);
1385 g_proxyProtocolMaximumSize = ::arg().asNum("proxy-protocol-maximum-size");
1386
1387 if (!::arg()["dns64-prefix"].empty()) {
1388 try {
1389 auto dns64Prefix = Netmask(::arg()["dns64-prefix"]);
1390 if (dns64Prefix.getBits() != 96) {
1391 g_log << Logger::Error << "Invalid prefix for 'dns64-prefix', the current implementation only supports /96 prefixes: " << ::arg()["dns64-prefix"] << endl;
1392 exit(1);
1393 }
1394 g_dns64Prefix = dns64Prefix.getNetwork();
1395 g_dns64PrefixReverse = reverseNameFromIP(*g_dns64Prefix);
1396 /* /96 is 24 nibbles + 2 for "ip6.arpa." */
1397 while (g_dns64PrefixReverse.countLabels() > 26) {
1398 g_dns64PrefixReverse.chopOff();
1399 }
1400 }
1401 catch (const NetmaskException& ne) {
1402 g_log << Logger::Error << "Invalid prefix '" << ::arg()["dns64-prefix"] << "' for 'dns64-prefix': " << ne.reason << endl;
1403 exit(1);
1404 }
1405 }
1406
1407 g_networkTimeoutMsec = ::arg().asNum("network-timeout");
1408
1409 std::tie(g_initialDomainMap, g_initialAllowNotifyFor) = parseZoneConfiguration();
1410
1411 g_latencyStatSize = ::arg().asNum("latency-statistic-size");
1412
1413 g_logCommonErrors = ::arg().mustDo("log-common-errors");
1414 g_logRPZChanges = ::arg().mustDo("log-rpz-changes");
1415
1416 g_anyToTcp = ::arg().mustDo("any-to-tcp");
1417 g_udpTruncationThreshold = ::arg().asNum("udp-truncation-threshold");
1418
1419 g_lowercaseOutgoing = ::arg().mustDo("lowercase-outgoing");
1420
1421 g_paddingFrom.toMasks(::arg()["edns-padding-from"]);
1422 if (::arg()["edns-padding-mode"] == "always") {
1423 g_paddingMode = PaddingMode::Always;
1424 }
1425 else if (::arg()["edns-padding-mode"] == "padded-queries-only") {
1426 g_paddingMode = PaddingMode::PaddedQueries;
1427 }
1428 else {
1429 g_log << Logger::Error << "Unknown edns-padding-mode: " << ::arg()["edns-padding-mode"] << endl;
1430 exit(1);
1431 }
1432 g_paddingTag = ::arg().asNum("edns-padding-tag");
1433
1434 RecThreadInfo::setNumDistributorThreads(::arg().asNum("distributor-threads"));
1435 RecThreadInfo::setNumWorkerThreads(::arg().asNum("threads"));
1436 if (RecThreadInfo::numWorkers() < 1) {
1437 g_log << Logger::Warning << "Asked to run with 0 threads, raising to 1 instead" << endl;
1438 RecThreadInfo::setNumWorkerThreads(1);
1439 }
1440
1441 g_maxMThreads = ::arg().asNum("max-mthreads");
1442
1443 int64_t maxInFlight = ::arg().asNum("max-concurrent-requests-per-tcp-connection");
1444 if (maxInFlight < 1 || maxInFlight > USHRT_MAX || maxInFlight >= g_maxMThreads) {
1445 g_log << Logger::Warning << "Asked to run with illegal max-concurrent-requests-per-tcp-connection, setting to default (10)" << endl;
1446 TCPConnection::s_maxInFlight = 10;
1447 }
1448 else {
1449 TCPConnection::s_maxInFlight = maxInFlight;
1450 }
1451
1452 int64_t millis = ::arg().asNum("tcp-out-max-idle-ms");
1453 TCPOutConnectionManager::s_maxIdleTime = timeval{millis / 1000, (static_cast<suseconds_t>(millis) % 1000) * 1000};
1454 TCPOutConnectionManager::s_maxIdlePerAuth = ::arg().asNum("tcp-out-max-idle-per-auth");
1455 TCPOutConnectionManager::s_maxQueries = ::arg().asNum("tcp-out-max-queries");
1456 TCPOutConnectionManager::s_maxIdlePerThread = ::arg().asNum("tcp-out-max-idle-per-thread");
1457
1458 g_gettagNeedsEDNSOptions = ::arg().mustDo("gettag-needs-edns-options");
1459
1460 s_statisticsInterval = ::arg().asNum("statistics-interval");
1461
1462 g_addExtendedResolutionDNSErrors = ::arg().mustDo("extended-resolution-errors");
1463
1464 if (::arg().asNum("aggressive-nsec-cache-size") > 0) {
1465 if (g_dnssecmode == DNSSECMode::ValidateAll || g_dnssecmode == DNSSECMode::ValidateForLog || g_dnssecmode == DNSSECMode::Process) {
1466 g_aggressiveNSECCache = make_unique<AggressiveNSECCache>(::arg().asNum("aggressive-nsec-cache-size"));
1467 }
1468 else {
1469 g_log << Logger::Warning << "Aggressive NSEC/NSEC3 caching is enabled but DNSSEC validation is not set to 'validate', 'log-fail' or 'process', ignoring" << endl;
1470 }
1471 }
1472
1473 {
1474 SuffixMatchNode dontThrottleNames;
1475 vector<string> parts;
1476 stringtok(parts, ::arg()["dont-throttle-names"], " ,");
1477 for (const auto& p : parts) {
1478 dontThrottleNames.add(DNSName(p));
1479 }
1480 g_dontThrottleNames.setState(std::move(dontThrottleNames));
1481
1482 parts.clear();
1483 NetmaskGroup dontThrottleNetmasks;
1484 stringtok(parts, ::arg()["dont-throttle-netmasks"], " ,");
1485 for (const auto& p : parts) {
1486 dontThrottleNetmasks.addMask(Netmask(p));
1487 }
1488 g_dontThrottleNetmasks.setState(std::move(dontThrottleNetmasks));
1489 }
1490
1491 {
1492 SuffixMatchNode xdnssecNames;
1493 vector<string> parts;
1494 stringtok(parts, ::arg()["x-dnssec-names"], " ,");
1495 for (const auto& p : parts) {
1496 xdnssecNames.add(DNSName(p));
1497 }
1498 g_xdnssec.setState(std::move(xdnssecNames));
1499 }
1500
1501 {
1502 SuffixMatchNode dotauthNames;
1503 vector<string> parts;
1504 stringtok(parts, ::arg()["dot-to-auth-names"], " ,");
1505 #ifndef HAVE_DNS_OVER_TLS
1506 if (parts.size()) {
1507 g_log << Logger::Error << "dot-to-auth-names setting contains names, but Recursor was built without DNS over TLS support. Setting will be ignored." << endl;
1508 }
1509 #endif
1510 for (const auto& p : parts) {
1511 dotauthNames.add(DNSName(p));
1512 }
1513 g_DoTToAuthNames.setState(std::move(dotauthNames));
1514 }
1515
1516 {
1517 CarbonConfig config;
1518 stringtok(config.servers, arg()["carbon-server"], ", ");
1519 config.hostname = arg()["carbon-ourname"];
1520 config.instance_name = arg()["carbon-instance"];
1521 config.namespace_name = arg()["carbon-namespace"];
1522 g_carbonConfig.setState(std::move(config));
1523 }
1524
1525 g_balancingFactor = ::arg().asDouble("distribution-load-factor");
1526 if (g_balancingFactor != 0.0 && g_balancingFactor < 1.0) {
1527 g_balancingFactor = 0.0;
1528 g_log << Logger::Warning << "Asked to run with a distribution-load-factor below 1.0, disabling it instead" << endl;
1529 }
1530
1531 #ifdef SO_REUSEPORT
1532 g_reusePort = ::arg().mustDo("reuseport");
1533 #endif
1534
1535 RecThreadInfo::infos().resize(RecThreadInfo::numHandlers() + RecThreadInfo::numDistributors() + RecThreadInfo::numWorkers() + RecThreadInfo::numTaskThreads());
1536
1537 if (g_reusePort) {
1538 if (RecThreadInfo::weDistributeQueries()) {
1539 /* first thread is the handler, then distributors */
1540 for (unsigned int threadId = 1; threadId <= RecThreadInfo::numDistributors(); threadId++) {
1541 auto& info = RecThreadInfo::info(threadId);
1542 auto& deferredAdds = info.deferredAdds;
1543 auto& tcpSockets = info.tcpSockets;
1544 makeUDPServerSockets(deferredAdds);
1545 makeTCPServerSockets(deferredAdds, tcpSockets);
1546 }
1547 }
1548 else {
1549 /* first thread is the handler, there is no distributor here and workers are accepting queries */
1550 for (unsigned int threadId = 1; threadId <= RecThreadInfo::numWorkers(); threadId++) {
1551 auto& info = RecThreadInfo::info(threadId);
1552 auto& deferredAdds = info.deferredAdds;
1553 auto& tcpSockets = info.tcpSockets;
1554 makeUDPServerSockets(deferredAdds);
1555 makeTCPServerSockets(deferredAdds, tcpSockets);
1556 }
1557 }
1558 }
1559 else {
1560 std::set<int> tcpSockets;
1561 /* we don't have reuseport so we can only open one socket per
1562 listening addr:port and everyone will listen on it */
1563 makeUDPServerSockets(g_deferredAdds);
1564 makeTCPServerSockets(g_deferredAdds, tcpSockets);
1565
1566 /* every listener (so distributor if g_weDistributeQueries, workers otherwise)
1567 needs to listen to the shared sockets */
1568 if (RecThreadInfo::weDistributeQueries()) {
1569 /* first thread is the handler, then distributors */
1570 for (unsigned int threadId = 1; threadId <= RecThreadInfo::numDistributors(); threadId++) {
1571 RecThreadInfo::info(threadId).tcpSockets = tcpSockets;
1572 }
1573 }
1574 else {
1575 /* first thread is the handler, there is no distributor here and workers are accepting queries */
1576 for (unsigned int threadId = 1; threadId <= RecThreadInfo::numWorkers(); threadId++) {
1577 RecThreadInfo::info(threadId).tcpSockets = tcpSockets;
1578 }
1579 }
1580 }
1581
1582 #ifdef NOD_ENABLED
1583 // Setup newly observed domain globals
1584 setupNODGlobal();
1585 #endif /* NOD_ENABLED */
1586
1587 int forks;
1588 for (forks = 0; forks < ::arg().asNum("processes") - 1; ++forks) {
1589 if (!fork()) // we are child
1590 break;
1591 }
1592
1593 if (::arg().mustDo("daemon")) {
1594 g_log << Logger::Warning << "Calling daemonize, going to background" << endl;
1595 g_log.toConsole(Logger::Critical);
1596 daemonize();
1597 }
1598 if (Utility::getpid() == 1) {
1599 /* We are running as pid 1, register sigterm and sigint handler
1600
1601 The Linux kernel will handle SIGTERM and SIGINT for all processes, except PID 1.
1602 It assumes that the processes running as pid 1 is an "init" like system.
1603 For years, this was a safe assumption, but containers change that: in
1604 most (all?) container implementations, the application itself is running
1605 as pid 1. This means that sending signals to those applications, will not
1606 be handled by default. Results might be "your container not responding
1607 when asking it to stop", or "ctrl-c not working even when the app is
1608 running in the foreground inside a container".
1609
1610 So TL;DR: If we're running pid 1 (container), we should handle SIGTERM and SIGINT ourselves */
1611
1612 signal(SIGTERM, termIntHandler);
1613 signal(SIGINT, termIntHandler);
1614 }
1615
1616 signal(SIGUSR1, usr1Handler);
1617 signal(SIGUSR2, usr2Handler);
1618 signal(SIGPIPE, SIG_IGN);
1619
1620 checkOrFixFDS();
1621
1622 #ifdef HAVE_LIBSODIUM
1623 if (sodium_init() == -1) {
1624 g_log << Logger::Error << "Unable to initialize sodium crypto library" << endl;
1625 exit(99);
1626 }
1627 #endif
1628
1629 openssl_thread_setup();
1630 openssl_seed();
1631 /* setup rng before chroot */
1632 dns_random_init();
1633
1634 if (::arg()["server-id"].empty()) {
1635 ::arg().set("server-id") = myHostname;
1636 }
1637
1638 int newgid = 0;
1639 if (!::arg()["setgid"].empty())
1640 newgid = strToGID(::arg()["setgid"]);
1641 int newuid = 0;
1642 if (!::arg()["setuid"].empty())
1643 newuid = strToUID(::arg()["setuid"]);
1644
1645 Utility::dropGroupPrivs(newuid, newgid);
1646
1647 if (!::arg()["chroot"].empty()) {
1648 #ifdef HAVE_SYSTEMD
1649 char* ns;
1650 ns = getenv("NOTIFY_SOCKET");
1651 if (ns != nullptr) {
1652 g_log << Logger::Error << "Unable to chroot when running from systemd. Please disable chroot= or set the 'Type' for this service to 'simple'" << endl;
1653 exit(1);
1654 }
1655 #endif
1656 if (chroot(::arg()["chroot"].c_str()) < 0 || chdir("/") < 0) {
1657 int err = errno;
1658 g_log << Logger::Error << "Unable to chroot to '" + ::arg()["chroot"] + "': " << strerror(err) << ", exiting" << endl;
1659 exit(1);
1660 }
1661 else
1662 g_log << Logger::Info << "Chrooted to '" << ::arg()["chroot"] << "'" << endl;
1663 }
1664
1665 checkSocketDir();
1666
1667 g_pidfname = ::arg()["socket-dir"] + "/" + g_programname + ".pid";
1668 if (!g_pidfname.empty())
1669 unlink(g_pidfname.c_str()); // remove possible old pid file
1670 writePid();
1671
1672 makeControlChannelSocket(::arg().asNum("processes") > 1 ? forks : -1);
1673
1674 Utility::dropUserPrivs(newuid);
1675 try {
1676 /* we might still have capabilities remaining, for example if we have been started as root
1677 without --setuid (please don't do that) or as an unprivileged user with ambient capabilities
1678 like CAP_NET_BIND_SERVICE.
1679 */
1680 dropCapabilities();
1681 }
1682 catch (const std::exception& e) {
1683 g_log << Logger::Warning << e.what() << endl;
1684 }
1685
1686 startLuaConfigDelayedThreads(delayedLuaThreads, g_luaconfs.getCopy().generation);
1687 delayedLuaThreads.rpzPrimaryThreads.clear(); // no longer needed
1688
1689 RecThreadInfo::makeThreadPipes();
1690
1691 g_tcpTimeout = ::arg().asNum("client-tcp-timeout");
1692 g_maxTCPPerClient = ::arg().asNum("max-tcp-per-client");
1693 g_tcpMaxQueriesPerConn = ::arg().asNum("max-tcp-queries-per-connection");
1694 g_maxUDPQueriesPerRound = ::arg().asNum("max-udp-queries-per-round");
1695
1696 g_useKernelTimestamp = ::arg().mustDo("protobuf-use-kernel-timestamp");
1697
1698 disableStats(StatComponent::API, ::arg()["stats-api-blacklist"]);
1699 disableStats(StatComponent::Carbon, ::arg()["stats-carbon-blacklist"]);
1700 disableStats(StatComponent::RecControl, ::arg()["stats-rec-control-blacklist"]);
1701 disableStats(StatComponent::SNMP, ::arg()["stats-snmp-blacklist"]);
1702
1703 disableStats(StatComponent::API, ::arg()["stats-api-disabled-list"]);
1704 disableStats(StatComponent::Carbon, ::arg()["stats-carbon-disabled-list"]);
1705 disableStats(StatComponent::RecControl, ::arg()["stats-rec-control-disabled-list"]);
1706 disableStats(StatComponent::SNMP, ::arg()["stats-snmp-disabled-list"]);
1707
1708 if (::arg().mustDo("snmp-agent")) {
1709 string setting = ::arg()["snmp-daemon-socket"];
1710 if (setting.empty()) {
1711 setting = ::arg()["snmp-master-socket"];
1712 }
1713 g_snmpAgent = std::make_shared<RecursorSNMPAgent>("recursor", setting);
1714 g_snmpAgent->run();
1715 }
1716
1717 int port = ::arg().asNum("udp-source-port-min");
1718 if (port < 1024 || port > 65535) {
1719 g_log << Logger::Error << "Unable to launch, udp-source-port-min is not a valid port number" << endl;
1720 exit(99); // this isn't going to fix itself either
1721 }
1722 g_minUdpSourcePort = port;
1723 port = ::arg().asNum("udp-source-port-max");
1724 if (port < 1024 || port > 65535 || port < g_minUdpSourcePort) {
1725 g_log << Logger::Error << "Unable to launch, udp-source-port-max is not a valid port number or is smaller than udp-source-port-min" << endl;
1726 exit(99); // this isn't going to fix itself either
1727 }
1728 g_maxUdpSourcePort = port;
1729 std::vector<string> parts{};
1730 stringtok(parts, ::arg()["udp-source-port-avoid"], ", ");
1731 for (const auto& part : parts) {
1732 port = std::stoi(part);
1733 if (port < 1024 || port > 65535) {
1734 g_log << Logger::Error << "Unable to launch, udp-source-port-avoid contains an invalid port number: " << part << endl;
1735 exit(99); // this isn't going to fix itself either
1736 }
1737 g_avoidUdpSourcePorts.insert(port);
1738 }
1739
1740 return RecThreadInfo::runThreads();
1741 }
1742
1743 static void handlePipeRequest(int fd, FDMultiplexer::funcparam_t& var)
1744 {
1745 ThreadMSG* tmsg = nullptr;
1746
1747 if (read(fd, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { // fd == readToThread || fd == readQueriesToThread
1748 unixDie("read from thread pipe returned wrong size or error");
1749 }
1750
1751 void* resp = 0;
1752 try {
1753 resp = tmsg->func();
1754 }
1755 catch (std::exception& e) {
1756 if (g_logCommonErrors)
1757 g_log << Logger::Error << "PIPE function we executed created exception: " << e.what() << endl; // but what if they wanted an answer.. we send 0
1758 }
1759 catch (PDNSException& e) {
1760 if (g_logCommonErrors)
1761 g_log << Logger::Error << "PIPE function we executed created PDNS exception: " << e.reason << endl; // but what if they wanted an answer.. we send 0
1762 }
1763 if (tmsg->wantAnswer) {
1764 if (write(RecThreadInfo::self().pipes.writeFromThread, &resp, sizeof(resp)) != sizeof(resp)) {
1765 delete tmsg;
1766 unixDie("write to thread pipe returned wrong size or error");
1767 }
1768 }
1769
1770 delete tmsg;
1771 }
1772
1773 static void handleRCC(int fd, FDMultiplexer::funcparam_t& var)
1774 {
1775 try {
1776 FDWrapper clientfd = accept(fd, nullptr, nullptr);
1777 if (clientfd == -1) {
1778 throw PDNSException("accept failed");
1779 }
1780 string msg = g_rcc.recv(clientfd).d_str;
1781 g_log << Logger::Info << "Received rec_control command '" << msg << "' via controlsocket" << endl;
1782
1783 RecursorControlParser rcp;
1784 RecursorControlParser::func_t* command;
1785 auto answer = rcp.getAnswer(clientfd, msg, &command);
1786
1787 g_rcc.send(clientfd, answer);
1788 command();
1789 }
1790 catch (const std::exception& e) {
1791 g_log << Logger::Error << "Error dealing with control socket request: " << e.what() << endl;
1792 }
1793 catch (const PDNSException& ae) {
1794 g_log << Logger::Error << "Error dealing with control socket request: " << ae.reason << endl;
1795 }
1796 }
1797
1798 class PeriodicTask
1799 {
1800 public:
1801 PeriodicTask(const string& n, time_t p) :
1802 period{p, 0}, name(n)
1803 {
1804 if (p <= 0) {
1805 throw PDNSException("Invalid period of periodic task " + n);
1806 }
1807 }
1808 void runIfDue(struct timeval& now, const std::function<void()>& f)
1809 {
1810 if (last_run < now - period) {
1811 // cerr << RecThreadInfo::id() << ' ' << name << ' ' << now.tv_sec << '.' << now.tv_usec << " running" << endl;
1812 f();
1813 Utility::gettimeofday(&last_run);
1814 now = last_run;
1815 }
1816 }
1817 void setPeriod(time_t p)
1818 {
1819 period.tv_sec = p;
1820 }
1821
1822 void updateLastRun()
1823 {
1824 Utility::gettimeofday(&last_run);
1825 }
1826
1827 bool hasRun() const
1828 {
1829 return last_run.tv_sec != 0 || last_run.tv_usec != 0;
1830 }
1831
1832 private:
1833 struct timeval last_run
1834 {
1835 0, 0
1836 };
1837 struct timeval period;
1838 const string name;
1839 };
1840
1841 static void houseKeeping(void*)
1842 {
1843 static thread_local bool t_running; // houseKeeping can get suspended in secpoll, and be restarted, which makes us do duplicate work
1844
1845 try {
1846 if (t_running) {
1847 return;
1848 }
1849 t_running = true;
1850
1851 struct timeval now;
1852 Utility::gettimeofday(&now);
1853
1854 // Below are the tasks that run for every recursorThread, including handler and taskThread
1855 static thread_local PeriodicTask packetCacheTask{"packetCacheTask", 5};
1856 packetCacheTask.runIfDue(now, []() {
1857 t_packetCache->doPruneTo(g_maxPacketCacheEntries / (RecThreadInfo::numDistributors() + RecThreadInfo::numWorkers()));
1858 });
1859
1860 // This is a full scan
1861 static thread_local PeriodicTask pruneNSpeedTask{"pruneNSSpeedTask", 100};
1862 pruneNSpeedTask.runIfDue(now, [now]() {
1863 SyncRes::pruneNSSpeeds(now.tv_sec - 300);
1864 });
1865
1866 static thread_local PeriodicTask pruneEDNSTask{"pruneEDNSTask", 5}; // period could likely be longer
1867 pruneEDNSTask.runIfDue(now, [now]() {
1868 SyncRes::pruneEDNSStatuses(now.tv_sec - 2 * 3600);
1869 });
1870
1871 static thread_local PeriodicTask pruneThrottledTask{"pruneThrottledTask", 5};
1872 pruneThrottledTask.runIfDue(now, []() {
1873 SyncRes::pruneThrottledServers();
1874 });
1875
1876 static thread_local PeriodicTask pruneTCPTask{"pruneTCPTask", 5};
1877 pruneTCPTask.runIfDue(now, [now]() {
1878 t_tcp_manager.cleanup(now);
1879 });
1880
1881 const auto& info = RecThreadInfo::self();
1882
1883 // Below are the thread specific tasks for the handler and the taskThread
1884 // Likley a few handler tasks could be moved to the taskThread
1885 if (info.isTaskThread()) {
1886 // TaskQueue is run always
1887 runTaskOnce(g_logCommonErrors);
1888
1889 static PeriodicTask ztcTask{"ZTC", 60};
1890 static map<DNSName, RecZoneToCache::State> ztcStates;
1891 auto luaconfsLocal = g_luaconfs.getLocal();
1892 ztcTask.runIfDue(now, [&luaconfsLocal]() {
1893 RecZoneToCache::maintainStates(luaconfsLocal->ztcConfigs, ztcStates, luaconfsLocal->generation);
1894 for (auto& ztc : luaconfsLocal->ztcConfigs) {
1895 RecZoneToCache::ZoneToCache(ztc.second, ztcStates.at(ztc.first));
1896 }
1897 });
1898 }
1899 else if (info.isHandler()) {
1900 static PeriodicTask recordCachePruneTask{"RecordCachePruneTask", 5};
1901 recordCachePruneTask.runIfDue(now, []() {
1902 g_recCache->doPrune(g_maxCacheEntries);
1903 });
1904
1905 static PeriodicTask negCachePruneTask{"NegCachePrunteTask", 5};
1906 negCachePruneTask.runIfDue(now, []() {
1907 g_negCache->prune(g_maxCacheEntries / 10);
1908 });
1909
1910 static PeriodicTask aggrNSECPruneTask{"AggrNSECPruneTask", 5};
1911 aggrNSECPruneTask.runIfDue(now, [now]() {
1912 if (g_aggressiveNSECCache) {
1913 g_aggressiveNSECCache->prune(now.tv_sec);
1914 }
1915 });
1916
1917 static PeriodicTask pruneFailedServersTask{"pruneFailedServerTask", 5};
1918 pruneFailedServersTask.runIfDue(now, [now]() {
1919 SyncRes::pruneFailedServers(now.tv_sec - SyncRes::s_serverdownthrottletime * 10);
1920 });
1921
1922 static PeriodicTask pruneNonResolvingTask{"pruneNonResolvingTask", 5};
1923 pruneNonResolvingTask.runIfDue(now, [now]() {
1924 SyncRes::pruneNonResolving(now.tv_sec - SyncRes::s_nonresolvingnsthrottletime);
1925 });
1926
1927 // Divide by 12 to get the original 2 hour cycle if s_maxcachettl is default (1 day)
1928 static PeriodicTask rootUpdateTask{"rootUpdateTask", std::max(SyncRes::s_maxcachettl / 12, 10U)};
1929 rootUpdateTask.runIfDue(now, [now]() {
1930 int res = SyncRes::getRootNS(now, nullptr, 0);
1931 if (res == 0) {
1932 try {
1933 primeRootNSZones(g_dnssecmode, 0);
1934 }
1935 catch (const std::exception& e) {
1936 g_log << Logger::Error << "Exception while priming the root NS zones: " << e.what() << endl;
1937 }
1938 catch (const PDNSException& e) {
1939 g_log << Logger::Error << "Exception while priming the root NS zones: " << e.reason << endl;
1940 }
1941 catch (const ImmediateServFailException& e) {
1942 g_log << Logger::Error << "Exception while priming the root NS zones: " << e.reason << endl;
1943 }
1944 catch (const PolicyHitException& e) {
1945 g_log << Logger::Error << "Policy hit while priming the root NS zones" << endl;
1946 }
1947 catch (...) {
1948 g_log << Logger::Error << "Exception while priming the root NS zones" << endl;
1949 }
1950 }
1951 });
1952
1953 static PeriodicTask secpollTask{"secpollTask", 3600};
1954 static time_t t_last_secpoll;
1955 secpollTask.runIfDue(now, []() {
1956 try {
1957 doSecPoll(&t_last_secpoll);
1958 }
1959 catch (const std::exception& e) {
1960 g_log << Logger::Error << "Exception while performing security poll: " << e.what() << endl;
1961 }
1962 catch (const PDNSException& e) {
1963 g_log << Logger::Error << "Exception while performing security poll: " << e.reason << endl;
1964 }
1965 catch (const ImmediateServFailException& e) {
1966 g_log << Logger::Error << "Exception while performing security poll: " << e.reason << endl;
1967 }
1968 catch (const PolicyHitException& e) {
1969 g_log << Logger::Error << "Policy hit while performing security poll" << endl;
1970 }
1971 catch (...) {
1972 g_log << Logger::Error << "Exception while performing security poll" << endl;
1973 }
1974 });
1975
1976 auto luaconfsLocal = g_luaconfs.getLocal();
1977 static PeriodicTask trustAnchorTask{"trustAnchorTask", std::max(1U, luaconfsLocal->trustAnchorFileInfo.interval) * 3600};
1978 if (!trustAnchorTask.hasRun()) {
1979 // Loading the Lua config file already "refreshed" the TAs
1980 trustAnchorTask.updateLastRun();
1981 }
1982 // interval might have ben updated
1983 trustAnchorTask.setPeriod(std::max(1U, luaconfsLocal->trustAnchorFileInfo.interval) * 3600);
1984 trustAnchorTask.runIfDue(now, [&luaconfsLocal]() {
1985 if (!luaconfsLocal->trustAnchorFileInfo.fname.empty() && luaconfsLocal->trustAnchorFileInfo.interval != 0) {
1986 g_log << Logger::Debug << "Refreshing Trust Anchors from file" << endl;
1987 try {
1988 map<DNSName, dsmap_t> dsAnchors;
1989 if (updateTrustAnchorsFromFile(luaconfsLocal->trustAnchorFileInfo.fname, dsAnchors)) {
1990 g_luaconfs.modify([&dsAnchors](LuaConfigItems& lci) {
1991 lci.dsAnchors = dsAnchors;
1992 });
1993 }
1994 }
1995 catch (const PDNSException& pe) {
1996 g_log << Logger::Error << "Unable to update Trust Anchors: " << pe.reason << endl;
1997 }
1998 }
1999 });
2000 }
2001 t_running = false;
2002 }
2003 catch (const PDNSException& ae) {
2004 t_running = false;
2005 g_log << Logger::Error << "Fatal error in housekeeping thread: " << ae.reason << endl;
2006 throw;
2007 }
2008 catch (...) {
2009 t_running = false;
2010 g_log << Logger::Error << "Uncaught exception in housekeeping thread" << endl;
2011 throw;
2012 }
2013 }
2014
2015 static void recursorThread()
2016 {
2017 try {
2018 auto& threadInfo = RecThreadInfo::self();
2019 {
2020 SyncRes tmp(g_now); // make sure it allocates tsstorage before we do anything, like primeHints or so..
2021 SyncRes::setDomainMap(g_initialDomainMap);
2022 t_allowFrom = g_initialAllowFrom;
2023 t_allowNotifyFrom = g_initialAllowNotifyFrom;
2024 t_allowNotifyFor = g_initialAllowNotifyFor;
2025 t_udpclientsocks = std::make_unique<UDPClientSocks>();
2026 t_tcpClientCounts = std::make_unique<tcpClientCounts_t>();
2027
2028 if (threadInfo.isHandler()) {
2029 if (!primeHints()) {
2030 threadInfo.setExitCode(EXIT_FAILURE);
2031 RecursorControlChannel::stop = 1;
2032 g_log << Logger::Critical << "Priming cache failed, stopping" << endl;
2033 }
2034 g_log << Logger::Debug << "Done priming cache with root hints" << endl;
2035 }
2036 }
2037
2038 t_packetCache = std::make_unique<RecursorPacketCache>();
2039
2040 #ifdef NOD_ENABLED
2041 if (threadInfo.isWorker())
2042 setupNODThread();
2043 #endif /* NOD_ENABLED */
2044
2045 /* the listener threads handle TCP queries */
2046 if (threadInfo.isWorker() || threadInfo.isListener()) {
2047 try {
2048 if (!::arg()["lua-dns-script"].empty()) {
2049 t_pdl = std::make_shared<RecursorLua4>();
2050 t_pdl->loadFile(::arg()["lua-dns-script"]);
2051 g_log << Logger::Warning << "Loaded 'lua' script from '" << ::arg()["lua-dns-script"] << "'" << endl;
2052 }
2053 }
2054 catch (std::exception& e) {
2055 g_log << Logger::Error << "Failed to load 'lua' script from '" << ::arg()["lua-dns-script"] << "': " << e.what() << endl;
2056 _exit(99);
2057 }
2058 }
2059
2060 unsigned int ringsize = ::arg().asNum("stats-ringbuffer-entries") / RecThreadInfo::numWorkers();
2061 if (ringsize) {
2062 t_remotes = std::make_unique<addrringbuf_t>();
2063 if (RecThreadInfo::weDistributeQueries())
2064 t_remotes->set_capacity(::arg().asNum("stats-ringbuffer-entries") / RecThreadInfo::numDistributors());
2065 else
2066 t_remotes->set_capacity(ringsize);
2067 t_servfailremotes = std::make_unique<addrringbuf_t>();
2068 t_servfailremotes->set_capacity(ringsize);
2069 t_bogusremotes = std::make_unique<addrringbuf_t>();
2070 t_bogusremotes->set_capacity(ringsize);
2071 t_largeanswerremotes = std::make_unique<addrringbuf_t>();
2072 t_largeanswerremotes->set_capacity(ringsize);
2073 t_timeouts = std::make_unique<addrringbuf_t>();
2074 t_timeouts->set_capacity(ringsize);
2075
2076 t_queryring = std::make_unique<boost::circular_buffer<pair<DNSName, uint16_t>>>();
2077 t_queryring->set_capacity(ringsize);
2078 t_servfailqueryring = std::make_unique<boost::circular_buffer<pair<DNSName, uint16_t>>>();
2079 t_servfailqueryring->set_capacity(ringsize);
2080 t_bogusqueryring = std::make_unique<boost::circular_buffer<pair<DNSName, uint16_t>>>();
2081 t_bogusqueryring->set_capacity(ringsize);
2082 }
2083 MT = std::make_unique<MT_t>(::arg().asNum("stack-size"));
2084 threadInfo.mt = MT.get();
2085
2086 /* start protobuf export threads if needed */
2087 auto luaconfsLocal = g_luaconfs.getLocal();
2088 checkProtobufExport(luaconfsLocal);
2089 checkOutgoingProtobufExport(luaconfsLocal);
2090 #ifdef HAVE_FSTRM
2091 checkFrameStreamExport(luaconfsLocal);
2092 #endif
2093
2094 t_fdm = unique_ptr<FDMultiplexer>(getMultiplexer());
2095
2096 std::unique_ptr<RecursorWebServer> rws;
2097
2098 t_fdm->addReadFD(threadInfo.pipes.readToThread, handlePipeRequest);
2099
2100 if (threadInfo.isHandler()) {
2101 if (::arg().mustDo("webserver")) {
2102 g_log << Logger::Warning << "Enabling web server" << endl;
2103 try {
2104 rws = make_unique<RecursorWebServer>(t_fdm.get());
2105 }
2106 catch (const PDNSException& e) {
2107 g_log << Logger::Error << "Unable to start the internal web server: " << e.reason << endl;
2108 _exit(99);
2109 }
2110 }
2111 g_log << Logger::Info << "Enabled '" << t_fdm->getName() << "' multiplexer" << endl;
2112 }
2113 else {
2114 t_fdm->addReadFD(threadInfo.pipes.readQueriesToThread, handlePipeRequest);
2115
2116 if (threadInfo.isListener()) {
2117 if (g_reusePort) {
2118 /* then every listener has its own FDs */
2119 for (const auto& deferred : threadInfo.deferredAdds) {
2120 t_fdm->addReadFD(deferred.first, deferred.second);
2121 }
2122 }
2123 else {
2124 /* otherwise all listeners are listening on the same ones */
2125 for (const auto& deferred : g_deferredAdds) {
2126 t_fdm->addReadFD(deferred.first, deferred.second);
2127 }
2128 }
2129 }
2130 }
2131
2132 registerAllStats();
2133
2134 if (threadInfo.isHandler()) {
2135 t_fdm->addReadFD(g_rcc.d_fd, handleRCC); // control channel
2136 }
2137
2138 unsigned int maxTcpClients = ::arg().asNum("max-tcp-clients");
2139
2140 bool listenOnTCP{true};
2141
2142 time_t last_stat = 0;
2143 time_t last_carbon = 0, last_lua_maintenance = 0;
2144 time_t carbonInterval = ::arg().asNum("carbon-interval");
2145 time_t luaMaintenanceInterval = ::arg().asNum("lua-maintenance-interval");
2146 s_counter.store(0); // used to periodically execute certain tasks
2147
2148 while (!RecursorControlChannel::stop) {
2149 while (MT->schedule(&g_now))
2150 ; // MTasker letting the mthreads do their thing
2151
2152 // Use primes, it avoid not being scheduled in cases where the counter has a regular pattern.
2153 // We want to call handler thread often, it gets scheduled about 2 times per second
2154 if (((threadInfo.isHandler() || threadInfo.isTaskThread()) && s_counter % 11 == 0) || s_counter % 499 == 0) {
2155 MT->makeThread(houseKeeping, 0);
2156 }
2157
2158 if (!(s_counter % 55)) {
2159 typedef vector<pair<int, FDMultiplexer::funcparam_t>> expired_t;
2160 expired_t expired = t_fdm->getTimeouts(g_now);
2161
2162 for (expired_t::iterator i = expired.begin(); i != expired.end(); ++i) {
2163 shared_ptr<TCPConnection> conn = boost::any_cast<shared_ptr<TCPConnection>>(i->second);
2164 if (g_logCommonErrors)
2165 g_log << Logger::Warning << "Timeout from remote TCP client " << conn->d_remote.toStringWithPort() << endl;
2166 t_fdm->removeReadFD(i->first);
2167 }
2168 }
2169
2170 s_counter++;
2171
2172 if (threadInfo.isHandler()) {
2173 if (statsWanted || (s_statisticsInterval > 0 && (g_now.tv_sec - last_stat) >= s_statisticsInterval)) {
2174 doStats();
2175 last_stat = g_now.tv_sec;
2176 }
2177
2178 Utility::gettimeofday(&g_now, nullptr);
2179
2180 if ((g_now.tv_sec - last_carbon) >= carbonInterval) {
2181 MT->makeThread(doCarbonDump, 0);
2182 last_carbon = g_now.tv_sec;
2183 }
2184 }
2185 if (t_pdl != nullptr) {
2186 // lua-dns-script directive is present, call the maintenance callback if needed
2187 /* remember that the listener threads handle TCP queries */
2188 if (threadInfo.isWorker() || threadInfo.isListener()) {
2189 // Only on threads processing queries
2190 if (g_now.tv_sec - last_lua_maintenance >= luaMaintenanceInterval) {
2191 t_pdl->maintenance();
2192 last_lua_maintenance = g_now.tv_sec;
2193 }
2194 }
2195 }
2196
2197 t_fdm->run(&g_now);
2198 // 'run' updates g_now for us
2199
2200 if (threadInfo.isListener()) {
2201 if (listenOnTCP) {
2202 if (TCPConnection::getCurrentConnections() > maxTcpClients) { // shutdown, too many connections
2203 for (const auto fd : threadInfo.tcpSockets) {
2204 t_fdm->removeReadFD(fd);
2205 }
2206 listenOnTCP = false;
2207 }
2208 }
2209 else {
2210 if (TCPConnection::getCurrentConnections() <= maxTcpClients) { // reenable
2211 for (const auto fd : threadInfo.tcpSockets) {
2212 t_fdm->addReadFD(fd, handleNewTCPQuestion);
2213 }
2214 listenOnTCP = true;
2215 }
2216 }
2217 }
2218 }
2219 }
2220 catch (PDNSException& ae) {
2221 g_log << Logger::Error << "Exception: " << ae.reason << endl;
2222 }
2223 catch (std::exception& e) {
2224 g_log << Logger::Error << "STL Exception: " << e.what() << endl;
2225 }
2226 catch (...) {
2227 g_log << Logger::Error << "any other exception in main: " << endl;
2228 }
2229 }
2230
2231 int main(int argc, char** argv)
2232 {
2233 g_argc = argc;
2234 g_argv = argv;
2235 g_stats.startupTime = time(0);
2236 Utility::srandom();
2237 versionSetProduct(ProductRecursor);
2238 reportBasicTypes();
2239 reportOtherTypes();
2240
2241 int ret = EXIT_SUCCESS;
2242
2243 try {
2244 #if HAVE_FIBER_SANITIZER
2245 // Asan needs more stack
2246 ::arg().set("stack-size", "stack size per mthread") = "400000";
2247 #else
2248 ::arg().set("stack-size", "stack size per mthread") = "200000";
2249 #endif
2250 ::arg().set("soa-minimum-ttl", "Don't change") = "0";
2251 ::arg().set("no-shuffle", "Don't change") = "off";
2252 ::arg().set("local-port", "port to listen on") = "53";
2253 ::arg().set("local-address", "IP addresses to listen on, separated by spaces or commas. Also accepts ports.") = "127.0.0.1";
2254 ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options") = "no";
2255 ::arg().set("trace", "if we should output heaps of logging. set to 'fail' to only log failing domains") = "off";
2256 ::arg().set("dnssec", "DNSSEC mode: off/process-no-validate/process (default)/log-fail/validate") = "process";
2257 ::arg().set("dnssec-log-bogus", "Log DNSSEC bogus validations") = "no";
2258 ::arg().set("signature-inception-skew", "Allow the signature inception to be off by this number of seconds") = "60";
2259 ::arg().set("daemon", "Operate as a daemon") = "no";
2260 ::arg().setSwitch("write-pid", "Write a PID file") = "yes";
2261 ::arg().set("loglevel", "Amount of logging. Higher is more. Do not set below 3") = "6";
2262 ::arg().set("disable-syslog", "Disable logging to syslog, useful when running inside a supervisor that logs stdout") = "no";
2263 ::arg().set("log-timestamp", "Print timestamps in log lines, useful to disable when running with a tool that timestamps stdout already") = "yes";
2264 ::arg().set("log-common-errors", "If we should log rather common errors") = "no";
2265 ::arg().set("chroot", "switch to chroot jail") = "";
2266 ::arg().set("setgid", "If set, change group id to this gid for more security"
2267 #ifdef HAVE_SYSTEMD
2268 #define SYSTEMD_SETID_MSG ". When running inside systemd, use the User and Group settings in the unit-file!"
2269 SYSTEMD_SETID_MSG
2270 #endif
2271 )
2272 = "";
2273 ::arg().set("setuid", "If set, change user id to this uid for more security"
2274 #ifdef HAVE_SYSTEMD
2275 SYSTEMD_SETID_MSG
2276 #endif
2277 )
2278 = "";
2279 ::arg().set("network-timeout", "Wait this number of milliseconds for network i/o") = "1500";
2280 ::arg().set("threads", "Launch this number of threads") = "2";
2281 ::arg().set("distributor-threads", "Launch this number of distributor threads, distributing queries to other threads") = "0";
2282 ::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!
2283 ::arg().set("config-name", "Name of this virtual configuration - will rename the binary image") = "";
2284 ::arg().set("api-config-dir", "Directory where REST API stores config and zones") = "";
2285 ::arg().set("api-key", "Static pre-shared authentication key for access to the REST API") = "";
2286 ::arg().setSwitch("webserver", "Start a webserver (for REST API)") = "no";
2287 ::arg().set("webserver-address", "IP Address of webserver to listen on") = "127.0.0.1";
2288 ::arg().set("webserver-port", "Port of webserver to listen on") = "8082";
2289 ::arg().set("webserver-password", "Password required for accessing the webserver") = "";
2290 ::arg().set("webserver-allow-from", "Webserver access is only allowed from these subnets") = "127.0.0.1,::1";
2291 ::arg().set("webserver-loglevel", "Amount of logging in the webserver (none, normal, detailed)") = "normal";
2292 ::arg().setSwitch("webserver-hash-plaintext-credentials", "Whether to hash passwords and api keys supplied in plaintext, to prevent keeping the plaintext version in memory at runtime") = "no";
2293 ::arg().set("carbon-ourname", "If set, overrides our reported hostname for carbon stats") = "";
2294 ::arg().set("carbon-server", "If set, send metrics in carbon (graphite) format to this server IP address") = "";
2295 ::arg().set("carbon-interval", "Number of seconds between carbon (graphite) updates") = "30";
2296 ::arg().set("carbon-namespace", "If set overwrites the first part of the carbon string") = "pdns";
2297 ::arg().set("carbon-instance", "If set overwrites the instance name default") = "recursor";
2298
2299 ::arg().set("statistics-interval", "Number of seconds between printing of recursor statistics, 0 to disable") = "1800";
2300 ::arg().set("quiet", "Suppress logging of questions and answers") = "";
2301 ::arg().set("logging-facility", "Facility to log messages as. 0 corresponds to local0") = "";
2302 ::arg().set("config-dir", "Location of configuration directory (recursor.conf)") = SYSCONFDIR;
2303 ::arg().set("socket-owner", "Owner of socket") = "";
2304 ::arg().set("socket-group", "Group of socket") = "";
2305 ::arg().set("socket-mode", "Permissions for socket") = "";
2306
2307 ::arg().set("socket-dir", string("Where the controlsocket will live, ") + LOCALSTATEDIR + "/pdns-recursor when unset and not chrooted"
2308 #ifdef HAVE_SYSTEMD
2309 + ". Set to the RUNTIME_DIRECTORY environment variable when that variable has a value (e.g. under systemd).")
2310 = "";
2311 auto runtimeDir = getenv("RUNTIME_DIRECTORY");
2312 if (runtimeDir != nullptr) {
2313 ::arg().set("socket-dir") = runtimeDir;
2314 }
2315 #else
2316 )
2317 = "";
2318 #endif
2319 ::arg().set("query-local-address", "Source IP address for sending queries") = "0.0.0.0";
2320 ::arg().set("client-tcp-timeout", "Timeout in seconds when talking to TCP clients") = "2";
2321 ::arg().set("max-mthreads", "Maximum number of simultaneous Mtasker threads") = "2048";
2322 ::arg().set("max-tcp-clients", "Maximum number of simultaneous TCP clients") = "128";
2323 ::arg().set("max-concurrent-requests-per-tcp-connection", "Maximum number of requests handled concurrently per TCP connection") = "10";
2324 ::arg().set("server-down-max-fails", "Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )") = "64";
2325 ::arg().set("server-down-throttle-time", "Number of seconds to throttle all queries to a server after being marked as down") = "60";
2326 ::arg().set("dont-throttle-names", "Do not throttle nameservers with this name or suffix") = "";
2327 ::arg().set("dont-throttle-netmasks", "Do not throttle nameservers with this IP netmask") = "";
2328 ::arg().set("non-resolving-ns-max-fails", "Number of failed address resolves of a nameserver to start throttling it, 0 is disabled") = "5";
2329 ::arg().set("non-resolving-ns-throttle-time", "Number of seconds to throttle a nameserver with a name failing to resolve") = "60";
2330
2331 ::arg().set("hint-file", "If set, load root hints from this file") = "";
2332 ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache") = "1000000";
2333 ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory") = "3600";
2334 ::arg().set("max-cache-bogus-ttl", "maximum number of seconds to keep a Bogus (positive or negative) cached entry in memory") = "3600";
2335 ::arg().set("max-cache-ttl", "maximum number of seconds to keep a cached entry in memory") = "86400";
2336 ::arg().set("packetcache-ttl", "maximum number of seconds to keep a cached entry in packetcache") = "3600";
2337 ::arg().set("max-packetcache-entries", "maximum number of entries to keep in the packetcache") = "500000";
2338 ::arg().set("packetcache-servfail-ttl", "maximum number of seconds to keep a cached servfail entry in packetcache") = "60";
2339 ::arg().set("server-id", "Returned when queried for 'id.server' TXT or NSID, defaults to hostname, set custom or 'disabled'") = "";
2340 ::arg().set("stats-ringbuffer-entries", "maximum number of packets to store statistics for") = "10000";
2341 ::arg().set("version-string", "string reported on version.pdns or version.bind") = fullVersionString();
2342 ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse") = LOCAL_NETS;
2343 ::arg().set("allow-from-file", "If set, load allowed netmasks from this file") = "";
2344 ::arg().set("allow-notify-for", "If set, NOTIFY requests for these zones will be allowed") = "";
2345 ::arg().set("allow-notify-for-file", "If set, load NOTIFY-allowed zones from this file") = "";
2346 ::arg().set("allow-notify-from", "If set, NOTIFY requests from these comma separated netmasks will be allowed") = "";
2347 ::arg().set("allow-notify-from-file", "If set, load NOTIFY-allowed netmasks from this file") = "";
2348 ::arg().set("entropy-source", "If set, read entropy from this file") = "/dev/urandom";
2349 ::arg().set("dont-query", "If set, do not query these netmasks for DNS data") = DONT_QUERY;
2350 ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)") = "0";
2351 ::arg().set("max-tcp-queries-per-connection", "If set, maximum number of TCP queries in a TCP connection") = "0";
2352 ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses") = "1";
2353 ::arg().set("single-socket", "If set, only use a single socket for outgoing queries") = "off";
2354 ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ") = "";
2355 ::arg().set("lua-config-file", "More powerful configuration options") = "";
2356 ::arg().setSwitch("allow-trust-anchor-query", "Allow queries for trustanchor.server CH TXT and negativetrustanchor.server CH TXT") = "no";
2357
2358 ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs") = "";
2359 ::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs") = "";
2360 ::arg().set("forward-zones-file", "File with (+)domain=ip pairs for forwarding") = "";
2361 ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts") = "off";
2362 ::arg().set("export-etc-hosts-search-suffix", "Also serve up the contents of /etc/hosts with this suffix") = "";
2363 ::arg().set("etc-hosts-file", "Path to 'hosts' file") = "/etc/hosts";
2364 ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space") = "yes";
2365 ::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers") = "";
2366 ::arg().set("lua-maintenance-interval", "Number of seconds between calls to the lua user defined maintenance() function") = "1";
2367 ::arg().set("latency-statistic-size", "Number of latency values to calculate the qa-latency average") = "10000";
2368 ::arg().setSwitch("disable-packetcache", "Disable packetcache") = "no";
2369 ::arg().set("ecs-ipv4-bits", "Number of bits of IPv4 address to pass for EDNS Client Subnet") = "24";
2370 ::arg().set("ecs-ipv4-cache-bits", "Maximum number of bits of IPv4 mask to cache ECS response") = "24";
2371 ::arg().set("ecs-ipv6-bits", "Number of bits of IPv6 address to pass for EDNS Client Subnet") = "56";
2372 ::arg().set("ecs-ipv6-cache-bits", "Maximum number of bits of IPv6 mask to cache ECS response") = "56";
2373 ::arg().setSwitch("ecs-ipv4-never-cache", "If we should never cache IPv4 ECS responses") = "no";
2374 ::arg().setSwitch("ecs-ipv6-never-cache", "If we should never cache IPv6 ECS responses") = "no";
2375 ::arg().set("ecs-minimum-ttl-override", "The minimum TTL for records in ECS-specific answers") = "1";
2376 ::arg().set("ecs-cache-limit-ttl", "Minimum TTL to cache ECS response") = "0";
2377 ::arg().set("edns-subnet-whitelist", "List of netmasks and domains that we should enable EDNS subnet for (deprecated)") = "";
2378 ::arg().set("edns-subnet-allow-list", "List of netmasks and domains that we should enable EDNS subnet for") = "";
2379 ::arg().set("ecs-add-for", "List of client netmasks for which EDNS Client Subnet will be added") = "0.0.0.0/0, ::/0, " LOCAL_NETS_INVERSE;
2380 ::arg().set("ecs-scope-zero-address", "Address to send to allow-listed authoritative servers for incoming queries with ECS prefix-length source of 0") = "";
2381 ::arg().setSwitch("use-incoming-edns-subnet", "Pass along received EDNS Client Subnet information") = "no";
2382 ::arg().setSwitch("pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads") = "yes";
2383 ::arg().setSwitch("root-nx-trust", "If set, believe that an NXDOMAIN from the root means the TLD does not exist") = "yes";
2384 ::arg().setSwitch("any-to-tcp", "Answer ANY queries with tc=1, shunting to TCP") = "no";
2385 ::arg().setSwitch("lowercase-outgoing", "Force outgoing questions to lowercase") = "no";
2386 ::arg().setSwitch("gettag-needs-edns-options", "If EDNS Options should be extracted before calling the gettag() hook") = "no";
2387 ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate") = "1232";
2388 ::arg().set("edns-outgoing-bufsize", "Outgoing EDNS buffer size") = "1232";
2389 ::arg().set("minimum-ttl-override", "The minimum TTL") = "1";
2390 ::arg().set("max-qperq", "Maximum outgoing queries per query") = "60";
2391 ::arg().set("max-ns-address-qperq", "Maximum outgoing NS address queries per query") = "10";
2392 ::arg().set("max-total-msec", "Maximum total wall-clock time per query in milliseconds, 0 for unlimited") = "7000";
2393 ::arg().set("max-recursion-depth", "Maximum number of internal recursion calls per query, 0 for unlimited") = "40";
2394 ::arg().set("max-udp-queries-per-round", "Maximum number of UDP queries processed per recvmsg() round, before returning back to normal processing") = "10000";
2395 ::arg().set("protobuf-use-kernel-timestamp", "Compute the latency of queries in protobuf messages by using the timestamp set by the kernel when the query was received (when available)") = "";
2396 ::arg().set("distribution-pipe-buffer-size", "Size in bytes of the internal buffer of the pipe used by the distributor to pass incoming queries to a worker thread") = "0";
2397
2398 ::arg().set("include-dir", "Include *.conf files from this directory") = "";
2399 ::arg().set("security-poll-suffix", "Domain name from which to query security update notifications") = "secpoll.powerdns.com.";
2400
2401 ::arg().setSwitch("reuseport", "Enable SO_REUSEPORT allowing multiple recursors processes to listen to 1 address") = "no";
2402
2403 ::arg().setSwitch("snmp-agent", "If set, register as an SNMP agent") = "no";
2404 ::arg().set("snmp-master-socket", "If set and snmp-agent is set, the socket to use to register to the SNMP daemon (deprecated)") = "";
2405 ::arg().set("snmp-daemon-socket", "If set and snmp-agent is set, the socket to use to register to the SNMP daemon") = "";
2406
2407 std::string defaultAPIDisabledStats = "cache-bytes, packetcache-bytes, special-memory-usage";
2408 for (size_t idx = 0; idx < 32; idx++) {
2409 defaultAPIDisabledStats += ", ecs-v4-response-bits-" + std::to_string(idx + 1);
2410 }
2411 for (size_t idx = 0; idx < 128; idx++) {
2412 defaultAPIDisabledStats += ", ecs-v6-response-bits-" + std::to_string(idx + 1);
2413 }
2414 std::string defaultDisabledStats = defaultAPIDisabledStats + ", cumul-clientanswers, cumul-authanswers, policy-hits";
2415
2416 ::arg().set("stats-api-blacklist", "List of statistics that are disabled when retrieving the complete list of statistics via the API (deprecated)") = defaultAPIDisabledStats;
2417 ::arg().set("stats-carbon-blacklist", "List of statistics that are prevented from being exported via Carbon (deprecated)") = defaultDisabledStats;
2418 ::arg().set("stats-rec-control-blacklist", "List of statistics that are prevented from being exported via rec_control get-all (deprecated)") = defaultDisabledStats;
2419 ::arg().set("stats-snmp-blacklist", "List of statistics that are prevented from being exported via SNMP (deprecated)") = defaultDisabledStats;
2420
2421 ::arg().set("stats-api-disabled-list", "List of statistics that are disabled when retrieving the complete list of statistics via the API") = defaultAPIDisabledStats;
2422 ::arg().set("stats-carbon-disabled-list", "List of statistics that are prevented from being exported via Carbon") = defaultDisabledStats;
2423 ::arg().set("stats-rec-control-disabled-list", "List of statistics that are prevented from being exported via rec_control get-all") = defaultDisabledStats;
2424 ::arg().set("stats-snmp-disabled-list", "List of statistics that are prevented from being exported via SNMP") = defaultDisabledStats;
2425
2426 ::arg().set("tcp-fast-open", "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size") = "0";
2427 ::arg().set("tcp-fast-open-connect", "Enable TCP Fast Open support on outgoing sockets") = "no";
2428 ::arg().set("nsec3-max-iterations", "Maximum number of iterations allowed for an NSEC3 record") = "150";
2429
2430 ::arg().set("cpu-map", "Thread to CPU mapping, space separated thread-id=cpu1,cpu2..cpuN pairs") = "";
2431
2432 ::arg().setSwitch("log-rpz-changes", "Log additions and removals to RPZ zones at Info level") = "no";
2433
2434 ::arg().set("xpf-allow-from", "XPF information is only processed from these subnets") = "";
2435 ::arg().set("xpf-rr-code", "XPF option code to use") = "0";
2436
2437 ::arg().set("proxy-protocol-from", "A Proxy Protocol header is only allowed from these subnets") = "";
2438 ::arg().set("proxy-protocol-maximum-size", "The maximum size of a proxy protocol payload, including the TLV values") = "512";
2439
2440 ::arg().set("dns64-prefix", "DNS64 prefix") = "";
2441
2442 ::arg().set("udp-source-port-min", "Minimum UDP port to bind on") = "1024";
2443 ::arg().set("udp-source-port-max", "Maximum UDP port to bind on") = "65535";
2444 ::arg().set("udp-source-port-avoid", "List of comma separated UDP port number to avoid") = "11211";
2445 ::arg().set("rng", "Specify random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.") = "auto";
2446 ::arg().set("public-suffix-list-file", "Path to the Public Suffix List file, if any") = "";
2447 ::arg().set("distribution-load-factor", "The load factor used when PowerDNS is distributing queries to worker threads") = "0.0";
2448
2449 ::arg().setSwitch("qname-minimization", "Use Query Name Minimization") = "yes";
2450 ::arg().setSwitch("nothing-below-nxdomain", "When an NXDOMAIN exists in cache for a name with fewer labels than the qname, send NXDOMAIN without doing a lookup (see RFC 8020)") = "dnssec";
2451 ::arg().set("max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file") = "0";
2452 ::arg().set("max-include-depth", "Maximum nested $INCLUDE depth when loading a zone from a file") = "20";
2453 ::arg().set("record-cache-shards", "Number of shards in the record cache") = "1024";
2454 ::arg().set("refresh-on-ttl-perc", "If a record is requested from the cache and only this % of original TTL remains, refetch") = "0";
2455
2456 ::arg().set("x-dnssec-names", "Collect DNSSEC statistics for names or suffixes in this list in separate x-dnssec counters") = "";
2457
2458 #ifdef NOD_ENABLED
2459 ::arg().set("new-domain-tracking", "Track newly observed domains (i.e. never seen before).") = "no";
2460 ::arg().set("new-domain-log", "Log newly observed domains.") = "yes";
2461 ::arg().set("new-domain-lookup", "Perform a DNS lookup newly observed domains as a subdomain of the configured domain") = "";
2462 ::arg().set("new-domain-history-dir", "Persist new domain tracking data here to persist between restarts") = string(NODCACHEDIR) + "/nod";
2463 ::arg().set("new-domain-whitelist", "List of domains (and implicitly all subdomains) which will never be considered a new domain (deprecated)") = "";
2464 ::arg().set("new-domain-ignore-list", "List of domains (and implicitly all subdomains) which will never be considered a new domain") = "";
2465 ::arg().set("new-domain-db-size", "Size of the DB used to track new domains in terms of number of cells. Defaults to 67108864") = "67108864";
2466 ::arg().set("new-domain-pb-tag", "If protobuf is configured, the tag to use for messages containing newly observed domains. Defaults to 'pdns-nod'") = "pdns-nod";
2467 ::arg().set("unique-response-tracking", "Track unique responses (tuple of query name, type and RR).") = "no";
2468 ::arg().set("unique-response-log", "Log unique responses") = "yes";
2469 ::arg().set("unique-response-history-dir", "Persist unique response tracking data here to persist between restarts") = string(NODCACHEDIR) + "/udr";
2470 ::arg().set("unique-response-db-size", "Size of the DB used to track unique responses in terms of number of cells. Defaults to 67108864") = "67108864";
2471 ::arg().set("unique-response-pb-tag", "If protobuf is configured, the tag to use for messages containing unique DNS responses. Defaults to 'pdns-udr'") = "pdns-udr";
2472 #endif /* NOD_ENABLED */
2473
2474 ::arg().setSwitch("extended-resolution-errors", "If set, send an EDNS Extended Error extension on resolution failures, like DNSSEC validation errors") = "no";
2475
2476 ::arg().set("aggressive-nsec-cache-size", "The number of records to cache in the aggressive cache. If set to a value greater than 0, and DNSSEC processing or validation is enabled, the recursor will cache NSEC and NSEC3 records to generate negative answers, as defined in rfc8198") = "100000";
2477
2478 ::arg().set("edns-padding-from", "List of netmasks (proxy IP in case of XPF or proxy-protocol presence, client IP otherwise) for which EDNS padding will be enabled in responses, provided that 'edns-padding-mode' applies") = "";
2479 ::arg().set("edns-padding-mode", "Whether to add EDNS padding to all responses ('always') or only to responses for queries containing the EDNS padding option ('padded-queries-only', the default). In both modes, padding will only be added to responses for queries coming from `edns-padding-from`_ sources") = "padded-queries-only";
2480 ::arg().set("edns-padding-tag", "Packetcache tag associated to responses sent with EDNS padding, to prevent sending these to clients for which padding is not enabled.") = "7830";
2481
2482 ::arg().setSwitch("dot-to-port-853", "Force DoT connection to target port 853 if DoT compiled in") = "yes";
2483 ::arg().set("dot-to-auth-names", "Use DoT to authoritative servers with these names or suffixes") = "";
2484 ::arg().set("event-trace-enabled", "If set, event traces are collected and send out via protobuf logging (1), logfile (2) or both(3)") = "0";
2485
2486 ::arg().set("tcp-out-max-idle-ms", "Time TCP/DoT connections are left idle in milliseconds or 0 if no limit") = "10000";
2487 ::arg().set("tcp-out-max-idle-per-auth", "Maximum number of idle TCP/DoT connections to a specific IP per thread, 0 means do not keep idle connections open") = "10";
2488 ::arg().set("tcp-out-max-queries", "Maximum total number of queries per TCP/DoT connection, 0 means no limit") = "0";
2489 ::arg().set("tcp-out-max-idle-per-thread", "Maximum number of idle TCP/DoT connections per thread") = "100";
2490 ::arg().setSwitch("structured-logging", "Prefer structured logging") = "yes";
2491
2492 ::arg().setCmd("help", "Provide a helpful message");
2493 ::arg().setCmd("version", "Print version string");
2494 ::arg().setCmd("config", "Output blank configuration");
2495 ::arg().setDefaults();
2496 g_log.toConsole(Logger::Info);
2497 ::arg().laxParse(argc, argv); // do a lax parse
2498
2499 if (::arg().mustDo("version")) {
2500 showProductVersion();
2501 showBuildConfiguration();
2502 exit(0);
2503 }
2504
2505 string configname = ::arg()["config-dir"] + "/recursor.conf";
2506 if (::arg()["config-name"] != "") {
2507 configname = ::arg()["config-dir"] + "/recursor-" + ::arg()["config-name"] + ".conf";
2508 g_programname += "-" + ::arg()["config-name"];
2509 }
2510 cleanSlashes(configname);
2511
2512 if (!::arg().getCommands().empty()) {
2513 cerr << "Fatal: non-option";
2514 if (::arg().getCommands().size() > 1) {
2515 cerr << "s";
2516 }
2517 cerr << " (";
2518 bool first = true;
2519 for (const auto& c : ::arg().getCommands()) {
2520 if (!first) {
2521 cerr << ", ";
2522 }
2523 first = false;
2524 cerr << c;
2525 }
2526 cerr << ") on the command line, perhaps a '--setting=123' statement missed the '='?" << endl;
2527 exit(99);
2528 }
2529
2530 if (::arg().mustDo("config")) {
2531 cout << ::arg().configstring(false, true);
2532 exit(0);
2533 }
2534
2535 g_slog = Logging::Logger::create(loggerBackend);
2536 auto startupLog = g_slog->withName("startup");
2537
2538 if (!::arg().file(configname.c_str())) {
2539 SLOG(g_log << Logger::Warning << "Unable to parse configuration file '" << configname << "'" << endl,
2540 startupLog->error("No such file", "Unable to parse configuration file", "config_file", Logging::Loggable(configname)));
2541 }
2542
2543 ::arg().parse(argc, argv);
2544
2545 if (!::arg()["chroot"].empty() && !::arg()["api-config-dir"].empty()) {
2546 SLOG(g_log << Logger::Error << "Using chroot and enabling the API is not possible" << endl,
2547 startupLog->info("Cannot use chroot and enable the API at the same time"));
2548 exit(EXIT_FAILURE);
2549 }
2550
2551 if (::arg()["socket-dir"].empty()) {
2552 if (::arg()["chroot"].empty())
2553 ::arg().set("socket-dir") = std::string(LOCALSTATEDIR) + "/pdns-recursor";
2554 else
2555 ::arg().set("socket-dir") = "/";
2556 }
2557
2558 if (::arg().asNum("threads") == 1) {
2559 if (::arg().mustDo("pdns-distributes-queries")) {
2560 SLOG(g_log << Logger::Warning << "Asked to run with pdns-distributes-queries set but no distributor threads, raising to 1" << endl,
2561 startupLog->v(1)->info("Only one thread, no need to distribute queries ourselves"));
2562 ::arg().set("pdns-distributes-queries") = "no";
2563 }
2564 }
2565
2566 if (::arg().mustDo("pdns-distributes-queries") && ::arg().asNum("distributor-threads") <= 0) {
2567 SLOG(g_log << Logger::Warning << "Asked to run with pdns-distributes-queries set but no distributor threads, raising to 1" << endl,
2568 startupLog->v(1)->info("Asked to run with pdns-distributes-queries set but no distributor threads, raising to 1"));
2569 ::arg().set("distributor-threads") = "1";
2570 }
2571
2572 if (!::arg().mustDo("pdns-distributes-queries")) {
2573 ::arg().set("distributor-threads") = "0";
2574 }
2575
2576 if (::arg().mustDo("help")) {
2577 cout << "syntax:" << endl
2578 << endl;
2579 cout << ::arg().helpstring(::arg()["help"]) << endl;
2580 exit(0);
2581 }
2582 g_recCache = std::make_unique<MemRecursorCache>(::arg().asNum("record-cache-shards"));
2583 g_negCache = std::make_unique<NegCache>(::arg().asNum("record-cache-shards"));
2584
2585 g_quiet = ::arg().mustDo("quiet");
2586 Logger::Urgency logUrgency = (Logger::Urgency)::arg().asNum("loglevel");
2587
2588 if (logUrgency < Logger::Error)
2589 logUrgency = Logger::Error;
2590 if (!g_quiet && logUrgency < Logger::Info) { // Logger::Info=6, Logger::Debug=7
2591 logUrgency = Logger::Info; // if you do --quiet=no, you need Info to also see the query log
2592 }
2593 g_log.setLoglevel(logUrgency);
2594 g_log.toConsole(logUrgency);
2595
2596 ret = serviceMain(argc, argv);
2597 }
2598 catch (PDNSException& ae) {
2599 g_log << Logger::Error << "Exception: " << ae.reason << endl;
2600 ret = EXIT_FAILURE;
2601 }
2602 catch (std::exception& e) {
2603 g_log << Logger::Error << "STL Exception: " << e.what() << endl;
2604 ret = EXIT_FAILURE;
2605 }
2606 catch (...) {
2607 g_log << Logger::Error << "any other exception in main: " << endl;
2608 ret = EXIT_FAILURE;
2609 }
2610
2611 return ret;
2612 }
2613
2614 static RecursorControlChannel::Answer* doReloadLuaScript()
2615 {
2616 string fname = ::arg()["lua-dns-script"];
2617 try {
2618 if (fname.empty()) {
2619 t_pdl.reset();
2620 g_log << Logger::Info << RecThreadInfo::id() << " Unloaded current lua script" << endl;
2621 return new RecursorControlChannel::Answer{0, string("unloaded\n")};
2622 }
2623 else {
2624 t_pdl = std::make_shared<RecursorLua4>();
2625 int err = t_pdl->loadFile(fname);
2626 if (err != 0) {
2627 string msg = std::to_string(RecThreadInfo::id()) + " Retaining current script, could not read '" + fname + "': " + stringerror(err);
2628 g_log << Logger::Error << msg << endl;
2629 return new RecursorControlChannel::Answer{1, msg + "\n"};
2630 }
2631 }
2632 }
2633 catch (std::exception& e) {
2634 g_log << Logger::Error << RecThreadInfo::id() << " Retaining current script, error from '" << fname << "': " << e.what() << endl;
2635 return new RecursorControlChannel::Answer{1, string("retaining current script, error from '" + fname + "': " + e.what() + "\n")};
2636 }
2637
2638 g_log << Logger::Warning << RecThreadInfo::id() << " (Re)loaded lua script from '" << fname << "'" << endl;
2639 return new RecursorControlChannel::Answer{0, string("(re)loaded '" + fname + "'\n")};
2640 }
2641
2642 RecursorControlChannel::Answer doQueueReloadLuaScript(vector<string>::const_iterator begin, vector<string>::const_iterator end)
2643 {
2644 if (begin != end)
2645 ::arg().set("lua-dns-script") = *begin;
2646
2647 return broadcastAccFunction<RecursorControlChannel::Answer>(doReloadLuaScript);
2648 }
2649
2650 static string* pleaseUseNewTraceRegex(const std::string& newRegex)
2651 try {
2652 if (newRegex.empty()) {
2653 t_traceRegex.reset();
2654 return new string("unset\n");
2655 }
2656 else {
2657 t_traceRegex = std::make_shared<Regex>(newRegex);
2658 return new string("ok\n");
2659 }
2660 }
2661 catch (PDNSException& ae) {
2662 return new string(ae.reason + "\n");
2663 }
2664
2665 string doTraceRegex(vector<string>::const_iterator begin, vector<string>::const_iterator end)
2666 {
2667 return broadcastAccFunction<string>([=] { return pleaseUseNewTraceRegex(begin != end ? *begin : ""); });
2668 }
2669
2670 static uint64_t* pleaseWipePacketCache(const DNSName& canon, bool subtree, uint16_t qtype)
2671 {
2672 return new uint64_t(t_packetCache->doWipePacketCache(canon, qtype, subtree));
2673 }
2674
2675 struct WipeCacheResult wipeCaches(const DNSName& canon, bool subtree, uint16_t qtype)
2676 {
2677 struct WipeCacheResult res;
2678
2679 try {
2680 res.record_count = g_recCache->doWipeCache(canon, subtree, qtype);
2681 res.packet_count = broadcastAccFunction<uint64_t>([=] { return pleaseWipePacketCache(canon, subtree, qtype); });
2682 res.negative_record_count = g_negCache->wipe(canon, subtree);
2683 if (g_aggressiveNSECCache) {
2684 g_aggressiveNSECCache->removeZoneInfo(canon, subtree);
2685 }
2686 }
2687 catch (const std::exception& e) {
2688 g_log << Logger::Warning << ", failed: " << e.what() << endl;
2689 }
2690
2691 return res;
2692 }