]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/auth-main.cc
Meson: Add systemd feature support for service files
[thirdparty/pdns.git] / pdns / auth-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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <cstdio>
26 #include <csignal>
27 #include <cstring>
28 #include <cstdlib>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <iostream>
34 #include <string>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <sys/resource.h>
38 #include <sys/time.h>
39 #include <sys/wait.h>
40 #include <cerrno>
41 #include <pthread.h>
42 #include <thread>
43 #include <unistd.h>
44 #include <sys/mman.h>
45 #include <fcntl.h>
46 #include <fstream>
47 #include <boost/algorithm/string.hpp>
48 #ifdef HAVE_LIBSODIUM
49 #include <sodium.h>
50 #endif
51 #ifdef HAVE_SYSTEMD
52 #include <systemd/sd-daemon.h>
53 #endif
54
55 #include "auth-main.hh"
56 #include "coverage.hh"
57 #include "secpoll-auth.hh"
58 #include "dynhandler.hh"
59 #include "dnsseckeeper.hh"
60 #include "threadname.hh"
61 #include "misc.hh"
62 #include "query-local-address.hh"
63 #include "trusted-notification-proxy.hh"
64 #include "packetcache.hh"
65 #include "packethandler.hh"
66 #include "opensslsigners.hh"
67 #include "dns.hh"
68 #include "dnsbackend.hh"
69 #include "ueberbackend.hh"
70 #include "dnspacket.hh"
71 #include "nameserver.hh"
72 #include "distributor.hh"
73 #include "logger.hh"
74 #include "arguments.hh"
75 #include "packethandler.hh"
76 #include "statbag.hh"
77 #include "tcpreceiver.hh"
78 #include "misc.hh"
79 #include "dynlistener.hh"
80 #include "dynhandler.hh"
81 #include "communicator.hh"
82 #include "dnsproxy.hh"
83 #include "utility.hh"
84 #include "dnsrecords.hh"
85 #include "version.hh"
86 #include "ws-auth.hh"
87
88 #ifdef HAVE_LUA_RECORDS
89 #include "minicurl.hh"
90 #endif /* HAVE_LUA_RECORDS */
91
92 time_t g_starttime;
93
94 string g_programname = "pdns"; // used in packethandler.cc
95
96 const char* funnytext = "*****************************************************************************\n"
97 "Ok, you just ran pdns-auth through 'strings' hoping to find funny messages. \n"
98 "Well, you found one. \n"
99 "Two ions are flying through their particle accelerator, says the one to the \n"
100 "other 'I think I've lost an electron!' \n"
101 "So the other one says, 'Are you sure?'. 'YEAH! I'M POSITIVE!' \n"
102 " \n"
103 " the pdns crew - pdns@powerdns.com\n"
104 "*****************************************************************************\n";
105
106 bool g_anyToTcp;
107 bool g_8bitDNS;
108 #ifdef HAVE_LUA_RECORDS
109 bool g_doLuaRecord;
110 int g_luaRecordExecLimit;
111 time_t g_luaHealthChecksInterval{5};
112 time_t g_luaHealthChecksExpireDelay{3600};
113 time_t g_luaConsistentHashesExpireDelay{86400};
114 time_t g_luaConsistentHashesCleanupInterval{3600};
115 #endif
116 #ifdef ENABLE_GSS_TSIG
117 bool g_doGssTSIG;
118 #endif
119 typedef Distributor<DNSPacket, DNSPacket, PacketHandler> DNSDistributor;
120
121 ArgvMap theArg;
122 StatBag S; //!< Statistics are gathered across PDNS via the StatBag class S
123 AuthPacketCache PC; //!< This is the main PacketCache, shared across all threads
124 AuthQueryCache QC;
125 AuthZoneCache g_zoneCache;
126 std::unique_ptr<DNSProxy> DP{nullptr};
127 static std::unique_ptr<DynListener> s_dynListener{nullptr};
128 CommunicatorClass Communicator;
129 static double avg_latency{0.0}, receive_latency{0.0}, cache_latency{0.0}, backend_latency{0.0}, send_latency{0.0};
130 static unique_ptr<TCPNameserver> s_tcpNameserver{nullptr};
131 static vector<DNSDistributor*> s_distributors;
132 static shared_ptr<UDPNameserver> s_udpNameserver{nullptr};
133 static vector<std::shared_ptr<UDPNameserver>> s_udpReceivers;
134 NetmaskGroup g_proxyProtocolACL;
135 size_t g_proxyProtocolMaximumSize;
136
137 ArgvMap& arg()
138 {
139 return theArg;
140 }
141
142 static void declareArguments()
143 {
144 ::arg().set("config-dir", "Location of configuration directory (pdns.conf)") = SYSCONFDIR;
145 ::arg().set("config-name", "Name of this virtual configuration - will rename the binary image") = "";
146 ::arg().set("socket-dir", string("Where the controlsocket will live, ") + LOCALSTATEDIR + "/pdns when unset and not chrooted"
147 #ifdef HAVE_SYSTEMD
148 + ". Set to the RUNTIME_DIRECTORY environment variable when that variable has a value (e.g. under systemd).")
149 = "";
150 auto runtimeDir = getenv("RUNTIME_DIRECTORY");
151 if (runtimeDir != nullptr) {
152 ::arg().set("socket-dir") = runtimeDir;
153 }
154 #else
155 )
156 = "";
157 #endif
158 ::arg().set("module-dir", "Default directory for modules") = PKGLIBDIR;
159 ::arg().set("chroot", "If set, chroot to this directory for more security") = "";
160 ::arg().set("logging-facility", "Log under a specific facility") = "";
161 ::arg().set("daemon", "Operate as a daemon") = "no";
162
163 ::arg().set("local-port", "The port on which we listen") = "53";
164 ::arg().setSwitch("dnsupdate", "Enable/Disable DNS update (RFC2136) support. Default is no.") = "no";
165 ::arg().setSwitch("write-pid", "Write a PID file") = "yes";
166 ::arg().set("allow-dnsupdate-from", "A global setting to allow DNS updates from these IP ranges.") = "127.0.0.0/8,::1";
167 ::arg().setSwitch("dnsupdate-require-tsig", "Require TSIG secured DNS updates. Default is no.") = "no";
168 ::arg().set("proxy-protocol-from", "A Proxy Protocol header is only allowed from these subnets, and is mandatory then too.") = "";
169 ::arg().set("proxy-protocol-maximum-size", "The maximum size of a proxy protocol payload, including the TLV values") = "512";
170 ::arg().setSwitch("send-signed-notify", "Send TSIG secured NOTIFY if TSIG key is configured for a zone") = "yes";
171 ::arg().set("allow-unsigned-notify", "Allow unsigned notifications for TSIG secured zones") = "yes"; // FIXME: change to 'no' later
172 ::arg().set("allow-unsigned-autoprimary", "Allow autoprimaries to create zones without TSIG signed NOTIFY") = "yes";
173 ::arg().setSwitch("forward-dnsupdate", "A global setting to allow DNS update packages that are for a Secondary zone, to be forwarded to the primary.") = "yes";
174 ::arg().setSwitch("log-dns-details", "If PDNS should log DNS non-erroneous details") = "no";
175 ::arg().setSwitch("log-dns-queries", "If PDNS should log all incoming DNS queries") = "no";
176 ::arg().set("local-address", "Local IP addresses to which we bind") = "0.0.0.0, ::";
177 ::arg().setSwitch("local-address-nonexist-fail", "Fail to start if one or more of the local-address's do not exist on this server") = "yes";
178 ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options") = "no";
179 ::arg().setSwitch("reuseport", "Enable higher performance on compliant kernels by using SO_REUSEPORT allowing each receiver thread to open its own socket") = "no";
180 ::arg().set("query-local-address", "Source IP addresses for sending queries") = "0.0.0.0 ::";
181 ::arg().set("overload-queue-length", "Maximum queuelength moving to packetcache only") = "0";
182 ::arg().set("max-queue-length", "Maximum queuelength before considering situation lost") = "5000";
183
184 ::arg().set("retrieval-threads", "Number of AXFR-retrieval threads for secondary operation") = "2";
185 ::arg().setSwitch("api", "Enable/disable the REST API (including HTTP listener)") = "no";
186 ::arg().set("api-key", "Static pre-shared authentication key for access to the REST API") = "";
187 ::arg().setSwitch("default-api-rectify", "Default API-RECTIFY value for zones") = "yes";
188 ::arg().setSwitch("dname-processing", "If we should support DNAME records") = "no";
189
190 ::arg().setCmd("help", "Provide a helpful message");
191 ::arg().setCmd("version", "Output version and compilation date");
192 ::arg().setCmd("config", "Provide configuration file on standard output");
193 ::arg().setCmd("list-modules", "Lists all modules available");
194 ::arg().setCmd("no-config", "Don't parse configuration file");
195
196 ::arg().set("version-string", "PowerDNS version in packets - full, anonymous, powerdns or custom") = "full";
197 ::arg().set("control-console", "Debugging switch - don't use") = "no"; // but I know you will!
198 ::arg().set("loglevel", "Amount of logging. Higher is more. Do not set below 3") = "4";
199 ::arg().setSwitch("loglevel-show", "Include log level indicator in log output") = "no";
200 ::arg().set("disable-syslog", "Disable logging to syslog, useful when running inside a supervisor that logs stderr") = "no";
201 ::arg().set("log-timestamp", "Print timestamps in log lines") = "yes";
202 ::arg().set("distributor-threads", "Default number of Distributor (backend) threads to start") = "3";
203 ::arg().set("signing-threads", "Default number of signer threads to start") = "3";
204 ::arg().setSwitch("workaround-11804", "Workaround for issue 11804: send single RR per AXFR chunk") = "no";
205 ::arg().set("receiver-threads", "Default number of receiver threads to start") = "1";
206 ::arg().set("queue-limit", "Maximum number of milliseconds to queue a query") = "1500";
207 ::arg().set("resolver", "Use this resolver for ALIAS and the internal stub resolver") = "no";
208 ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate") = "1232";
209
210 ::arg().set("config-name", "Name of this virtual configuration - will rename the binary image") = "";
211
212 ::arg().set("load-modules", "Load this module - supply absolute or relative path") = "";
213 ::arg().set("launch", "Which backends to launch and order to query them in") = "";
214 ::arg().setSwitch("disable-axfr", "Disable zonetransfers but do allow TCP queries") = "no";
215 ::arg().set("allow-axfr-ips", "Allow zonetransfers only to these subnets") = "127.0.0.0/8,::1";
216 ::arg().set("only-notify", "Only send AXFR NOTIFY to these IP addresses or netmasks") = "0.0.0.0/0,::/0";
217 ::arg().set("also-notify", "When notifying a zone, also notify these nameservers") = "";
218 ::arg().set("allow-notify-from", "Allow AXFR NOTIFY from these IP ranges. If empty, drop all incoming notifies.") = "0.0.0.0/0,::/0";
219 ::arg().set("xfr-cycle-interval", "Schedule primary/secondary SOA freshness checks once every .. seconds") = "60";
220 ::arg().set("secondary-check-signature-freshness", "Check signatures in SOA freshness check. Sets DO flag on SOA queries. Outside some very problematic scenarios, say yes here.") = "yes";
221
222 ::arg().set("tcp-control-address", "If set, PowerDNS can be controlled over TCP on this address") = "";
223 ::arg().set("tcp-control-port", "If set, PowerDNS can be controlled over TCP on this address") = "53000";
224 ::arg().set("tcp-control-secret", "If set, PowerDNS can be controlled over TCP after passing this secret") = "";
225 ::arg().set("tcp-control-range", "If set, remote control of PowerDNS is possible over these networks only") = "127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10";
226
227 ::arg().setSwitch("secondary", "Act as a secondary") = "no";
228 ::arg().setSwitch("primary", "Act as a primary") = "no";
229 ::arg().setSwitch("autosecondary", "Act as an autosecondary") = "no";
230 ::arg().setSwitch("disable-axfr-rectify", "Disable the rectify step during an outgoing AXFR. Only required for regression testing.") = "no";
231 ::arg().setSwitch("guardian", "Run within a guardian process") = "no";
232 ::arg().setSwitch("prevent-self-notification", "Don't send notifications to what we think is ourself") = "yes";
233 ::arg().setSwitch("any-to-tcp", "Answer ANY queries with tc=1, shunting to TCP") = "yes";
234 ::arg().setSwitch("edns-subnet-processing", "If we should act on EDNS Subnet options") = "no";
235 ::arg().set("delay-notifications", "Configure a delay to send out notifications, no delay by default") = "0";
236
237 ::arg().set("edns-cookie-secret", "When set, set a server cookie when responding to a query with a Client cookie (in hex)") = "";
238
239 ::arg().setSwitch("webserver", "Start a webserver for monitoring (api=yes also enables the HTTP listener)") = "no";
240 ::arg().setSwitch("webserver-print-arguments", "If the webserver should print arguments") = "no";
241 ::arg().set("webserver-address", "IP Address of webserver/API to listen on") = "127.0.0.1";
242 ::arg().set("webserver-port", "Port of webserver/API to listen on") = "8081";
243 ::arg().set("webserver-password", "Password required for accessing the webserver") = "";
244 ::arg().set("webserver-allow-from", "Webserver/API access is only allowed from these subnets") = "127.0.0.1,::1";
245 ::arg().set("webserver-loglevel", "Amount of logging in the webserver (none, normal, detailed)") = "normal";
246 ::arg().set("webserver-max-bodysize", "Webserver/API maximum request/response body size in megabytes") = "2";
247 ::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";
248
249 ::arg().setSwitch("query-logging", "Hint backends that queries should be logged") = "no";
250
251 ::arg().set("carbon-namespace", "If set overwrites the first part of the carbon string") = "pdns";
252 ::arg().set("carbon-ourname", "If set, overrides our reported hostname for carbon stats") = "";
253 ::arg().set("carbon-instance", "If set overwrites the instance name default") = "auth";
254 ::arg().set("carbon-server", "If set, send metrics in carbon (graphite) format to this server IP address") = "";
255 ::arg().set("carbon-interval", "Number of seconds between carbon (graphite) updates") = "30";
256
257 ::arg().set("cache-ttl", "Seconds to store packets in the PacketCache") = "20";
258 ::arg().set("negquery-cache-ttl", "Seconds to store negative query results in the QueryCache") = "60";
259 ::arg().set("query-cache-ttl", "Seconds to store query results in the QueryCache") = "20";
260 ::arg().set("zone-cache-refresh-interval", "Seconds to cache list of known zones") = "300";
261 ::arg().set("server-id", "Returned when queried for 'id.server' TXT or NSID, defaults to hostname - disabled or custom") = "";
262 ::arg().set("default-soa-content", "Default SOA content") = "a.misconfigured.dns.server.invalid hostmaster.@ 0 10800 3600 604800 3600";
263 ::arg().set("default-soa-edit", "Default SOA-EDIT value") = "";
264 ::arg().set("default-soa-edit-signed", "Default SOA-EDIT value for signed zones") = "";
265 ::arg().set("dnssec-key-cache-ttl", "Seconds to cache DNSSEC keys from the database") = "30";
266 ::arg().set("domain-metadata-cache-ttl", "Seconds to cache zone metadata from the database") = "";
267 ::arg().set("zone-metadata-cache-ttl", "Seconds to cache zone metadata from the database") = "60";
268
269 ::arg().set("trusted-notification-proxy", "IP address of incoming notification proxy") = "";
270 ::arg().set("secondary-do-renotify", "If this secondary should send out notifications after receiving zone transfers from a primary") = "no";
271 ::arg().set("forward-notify", "IP addresses to forward received notifications to regardless of primary or secondary settings") = "";
272
273 ::arg().set("default-ttl", "Seconds a result is valid if not set otherwise") = "3600";
274 ::arg().set("max-tcp-connections", "Maximum number of TCP connections") = "20";
275 ::arg().set("max-tcp-connections-per-client", "Maximum number of simultaneous TCP connections per client") = "0";
276 ::arg().set("max-tcp-transactions-per-conn", "Maximum number of subsequent queries per TCP connection") = "0";
277 ::arg().set("max-tcp-connection-duration", "Maximum time in seconds that a TCP DNS connection is allowed to stay open.") = "0";
278 ::arg().set("tcp-idle-timeout", "Maximum time in seconds that a TCP DNS connection is allowed to stay open while being idle") = "5";
279
280 ::arg().setSwitch("no-shuffle", "Set this to prevent random shuffling of answers - for regression testing") = "off";
281
282 ::arg().set("setuid", "If set, change user id to this uid for more security") = "";
283 ::arg().set("setgid", "If set, change group id to this gid for more security") = "";
284
285 ::arg().set("max-cache-entries", "Maximum number of entries in the query cache") = "1000000";
286 ::arg().set("max-packet-cache-entries", "Maximum number of entries in the packet cache") = "1000000";
287 ::arg().set("max-signature-cache-entries", "Maximum number of signatures cache entries") = "";
288 ::arg().set("max-ent-entries", "Maximum number of empty non-terminals in a zone") = "100000";
289 ::arg().set("entropy-source", "If set, read entropy from this file") = "/dev/urandom";
290
291 ::arg().set("lua-prequery-script", "Lua script with prequery handler (DO NOT USE)") = "";
292 ::arg().set("lua-dnsupdate-policy-script", "Lua script with DNS update policy handler") = "";
293
294 ::arg().setSwitch("traceback-handler", "Enable the traceback handler (Linux only)") = "yes";
295 ::arg().setSwitch("direct-dnskey", "Fetch DNSKEY, CDS and CDNSKEY RRs from backend during DNSKEY or CDS/CDNSKEY synthesis") = "no";
296 ::arg().set("default-ksk-algorithm", "Default KSK algorithm") = "ecdsa256";
297 ::arg().set("default-ksk-size", "Default KSK size (0 means default)") = "0";
298 ::arg().set("default-zsk-algorithm", "Default ZSK algorithm") = "";
299 ::arg().set("default-zsk-size", "Default ZSK size (0 means default)") = "0";
300 ::arg().set("max-nsec3-iterations", "Limit the number of NSEC3 hash iterations") = "100";
301 ::arg().set("default-publish-cdnskey", "Default value for PUBLISH-CDNSKEY") = "";
302 ::arg().set("default-publish-cds", "Default value for PUBLISH-CDS") = "";
303
304 ::arg().set("include-dir", "Include *.conf files from this directory");
305 ::arg().set("security-poll-suffix", "Zone name from which to query security update notifications") = "secpoll.powerdns.com.";
306
307 ::arg().setSwitch("expand-alias", "Expand ALIAS records") = "no";
308 ::arg().set("outgoing-axfr-expand-alias", "Expand ALIAS records during outgoing AXFR") = "no";
309 ::arg().setSwitch("8bit-dns", "Allow 8bit dns queries") = "no";
310 #ifdef HAVE_LUA_RECORDS
311 ::arg().setSwitch("enable-lua-records", "Process LUA records for all zones (metadata overrides this)") = "no";
312 ::arg().set("lua-records-exec-limit", "LUA records scripts execution limit (instructions count). Values <= 0 mean no limit") = "1000";
313 ::arg().set("lua-health-checks-expire-delay", "Stops doing health checks after the record hasn't been used for that delay (in seconds)") = "3600";
314 ::arg().set("lua-health-checks-interval", "LUA records health checks monitoring interval in seconds") = "5";
315 ::arg().set("lua-consistent-hashes-cleanup-interval", "Pre-computed hashes cleanup interval (in seconds)") = "3600";
316 ::arg().set("lua-consistent-hashes-expire-delay", "Cleanup pre-computed hashes that haven't been used for the given delay (in seconds). See pickchashed() LUA function") = "86400";
317 #endif
318 ::arg().setSwitch("axfr-lower-serial", "Also AXFR a zone from a primary with a lower serial") = "no";
319
320 ::arg().set("lua-axfr-script", "Script to be used to edit incoming AXFRs") = "";
321 ::arg().set("xfr-max-received-mbytes", "Maximum number of megabytes received from an incoming XFR") = "100";
322 ::arg().set("axfr-fetch-timeout", "Maximum time in seconds for inbound AXFR to start or be idle after starting") = "10";
323
324 ::arg().set("tcp-fast-open", "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size") = "0";
325
326 ::arg().set("max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file") = "0";
327 ::arg().set("max-include-depth", "Maximum number of nested $INCLUDE directives while processing a zone file") = "20";
328 ::arg().setSwitch("upgrade-unknown-types", "Transparently upgrade known TYPExxx records. Recommended to keep off, except for PowerDNS upgrades until data sources are cleaned up") = "no";
329 ::arg().setSwitch("svc-autohints", "Transparently fill ipv6hint=auto ipv4hint=auto SVC params with AAAA/A records for the target name of the record (if within the same zone)") = "no";
330
331 ::arg().setSwitch("consistent-backends", "Assume individual zones are not divided over backends. Send only ANY lookup operations to the backend to reduce the number of lookups") = "yes";
332
333 ::arg().set("rng", "Specify the random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.") = "auto";
334
335 ::arg().set("default-catalog-zone", "Catalog zone to assign newly created primary zones (via the API) to") = "";
336
337 #ifdef ENABLE_GSS_TSIG
338 ::arg().setSwitch("enable-gss-tsig", "Enable GSS TSIG processing") = "no";
339 #endif
340 ::arg().setDefaults();
341 }
342
343 static time_t s_start = time(nullptr);
344 static uint64_t uptimeOfProcess(const std::string& /* str */)
345 {
346 return time(nullptr) - s_start;
347 }
348
349 static uint64_t getSysUserTimeMsec(const std::string& str)
350 {
351 struct rusage ru;
352 getrusage(RUSAGE_SELF, &ru);
353
354 if (str == "sys-msec") {
355 return (ru.ru_stime.tv_sec * 1000ULL + ru.ru_stime.tv_usec / 1000);
356 }
357 else
358 return (ru.ru_utime.tv_sec * 1000ULL + ru.ru_utime.tv_usec / 1000);
359 }
360
361 static uint64_t getTCPConnectionCount(const std::string& /* str */)
362 {
363 return s_tcpNameserver->numTCPConnections();
364 }
365
366 static uint64_t getQCount(const std::string& /* str */)
367 try {
368 int totcount = 0;
369 for (const auto& d : s_distributors) {
370 if (!d)
371 continue;
372 totcount += d->getQueueSize(); // this does locking and other things, so don't get smart
373 }
374 return totcount;
375 }
376 catch (std::exception& e) {
377 g_log << Logger::Error << "Had error retrieving queue sizes: " << e.what() << endl;
378 return 0;
379 }
380 catch (PDNSException& e) {
381 g_log << Logger::Error << "Had error retrieving queue sizes: " << e.reason << endl;
382 return 0;
383 }
384
385 static uint64_t getLatency(const std::string& /* str */)
386 {
387 return round(avg_latency);
388 }
389
390 static uint64_t getReceiveLatency(const std::string& /* str */)
391 {
392 return round(receive_latency);
393 }
394
395 static uint64_t getCacheLatency(const std::string& /* str */)
396 {
397 return round(cache_latency);
398 }
399
400 static uint64_t getBackendLatency(const std::string& /* str */)
401 {
402 return round(backend_latency);
403 }
404
405 static uint64_t getSendLatency(const std::string& /* str */)
406 {
407 return round(send_latency);
408 }
409
410 static void declareStats()
411 {
412 S.declare("udp-queries", "Number of UDP queries received");
413 S.declare("udp-do-queries", "Number of UDP queries received with DO bit");
414 S.declare("udp-cookie-queries", "Number of UDP queries received with the COOKIE EDNS option");
415 S.declare("udp-answers", "Number of answers sent out over UDP");
416 S.declare("udp-answers-bytes", "Total size of answers sent out over UDP");
417 S.declare("udp4-answers-bytes", "Total size of answers sent out over UDPv4");
418 S.declare("udp6-answers-bytes", "Total size of answers sent out over UDPv6");
419
420 S.declare("udp4-answers", "Number of IPv4 answers sent out over UDP");
421 S.declare("udp4-queries", "Number of IPv4 UDP queries received");
422 S.declare("udp6-answers", "Number of IPv6 answers sent out over UDP");
423 S.declare("udp6-queries", "Number of IPv6 UDP queries received");
424 S.declare("overload-drops", "Queries dropped because backends overloaded");
425
426 S.declare("rd-queries", "Number of recursion desired questions");
427 S.declare("recursion-unanswered", "Number of packets unanswered by configured recursor");
428 S.declare("recursing-answers", "Number of recursive answers sent out");
429 S.declare("recursing-questions", "Number of questions sent to recursor");
430 S.declare("corrupt-packets", "Number of corrupt packets received");
431 S.declare("signatures", "Number of DNSSEC signatures made");
432 S.declare("tcp-queries", "Number of TCP queries received");
433 S.declare("tcp-cookie-queries", "Number of TCP queries received with the COOKIE option");
434 S.declare("tcp-answers", "Number of answers sent out over TCP");
435 S.declare("tcp-answers-bytes", "Total size of answers sent out over TCP");
436 S.declare("tcp4-answers-bytes", "Total size of answers sent out over TCPv4");
437 S.declare("tcp6-answers-bytes", "Total size of answers sent out over TCPv6");
438
439 S.declare("tcp4-queries", "Number of IPv4 TCP queries received");
440 S.declare("tcp4-answers", "Number of IPv4 answers sent out over TCP");
441
442 S.declare("tcp6-queries", "Number of IPv6 TCP queries received");
443 S.declare("tcp6-answers", "Number of IPv6 answers sent out over TCP");
444
445 S.declare("open-tcp-connections", "Number of currently open TCP connections", getTCPConnectionCount, StatType::gauge);
446
447 S.declare("qsize-q", "Number of questions waiting for database attention", getQCount, StatType::gauge);
448
449 S.declare("dnsupdate-queries", "DNS update packets received.");
450 S.declare("dnsupdate-answers", "DNS update packets successfully answered.");
451 S.declare("dnsupdate-refused", "DNS update packets that are refused.");
452 S.declare("dnsupdate-changes", "DNS update changes to records in total.");
453
454 S.declare("incoming-notifications", "NOTIFY packets received.");
455
456 S.declare("uptime", "Uptime of process in seconds", uptimeOfProcess, StatType::counter);
457 S.declare("real-memory-usage", "Actual unique use of memory in bytes (approx)", getRealMemoryUsage, StatType::gauge);
458 S.declare("special-memory-usage", "Actual unique use of memory in bytes (approx)", getSpecialMemoryUsage, StatType::gauge);
459 S.declare("fd-usage", "Number of open filedescriptors", getOpenFileDescriptors, StatType::gauge);
460 #ifdef __linux__
461 S.declare("udp-recvbuf-errors", "UDP 'recvbuf' errors", udpErrorStats, StatType::counter);
462 S.declare("udp-sndbuf-errors", "UDP 'sndbuf' errors", udpErrorStats, StatType::counter);
463 S.declare("udp-noport-errors", "UDP 'noport' errors", udpErrorStats, StatType::counter);
464 S.declare("udp-in-errors", "UDP 'in' errors", udpErrorStats, StatType::counter);
465 S.declare("udp-in-csum-errors", "UDP 'in checksum' errors", udpErrorStats, StatType::counter);
466 S.declare("udp6-in-errors", "UDP 'in' errors over IPv6", udp6ErrorStats, StatType::counter);
467 S.declare("udp6-recvbuf-errors", "UDP 'recvbuf' errors over IPv6", udp6ErrorStats, StatType::counter);
468 S.declare("udp6-sndbuf-errors", "UDP 'sndbuf' errors over IPv6", udp6ErrorStats, StatType::counter);
469 S.declare("udp6-noport-errors", "UDP 'noport' errors over IPv6", udp6ErrorStats, StatType::counter);
470 S.declare("udp6-in-csum-errors", "UDP 'in checksum' errors over IPv6", udp6ErrorStats, StatType::counter);
471 #endif
472
473 S.declare("sys-msec", "Number of msec spent in system time", getSysUserTimeMsec, StatType::counter);
474 S.declare("user-msec", "Number of msec spent in user time", getSysUserTimeMsec, StatType::counter);
475
476 #ifdef __linux__
477 S.declare("cpu-iowait", "Time spent waiting for I/O to complete by the whole system, in units of USER_HZ", getCPUIOWait, StatType::counter);
478 S.declare("cpu-steal", "Stolen time, which is the time spent by the whole system in other operating systems when running in a virtualized environment, in units of USER_HZ", getCPUSteal, StatType::counter);
479 #endif
480
481 S.declare("meta-cache-size", "Number of entries in the metadata cache", DNSSECKeeper::dbdnssecCacheSizes, StatType::gauge);
482 S.declare("key-cache-size", "Number of entries in the key cache", DNSSECKeeper::dbdnssecCacheSizes, StatType::gauge);
483 S.declare("signature-cache-size", "Number of entries in the signature cache", signatureCacheSize, StatType::gauge);
484
485 S.declare("nxdomain-packets", "Number of times an NXDOMAIN packet was sent out");
486 S.declare("noerror-packets", "Number of times a NOERROR packet was sent out");
487 S.declare("servfail-packets", "Number of times a server-failed packet was sent out");
488 S.declare("unauth-packets", "Number of times a zone we are not auth for was queried");
489 S.declare("latency", "Average number of microseconds needed to answer a question", getLatency, StatType::gauge);
490 S.declare("receive-latency", "Average number of microseconds needed to receive a query", getReceiveLatency, StatType::gauge);
491 S.declare("cache-latency", "Average number of microseconds needed for a packet cache lookup", getCacheLatency, StatType::gauge);
492 S.declare("backend-latency", "Average number of microseconds needed for a backend lookup", getBackendLatency, StatType::gauge);
493 S.declare("send-latency", "Average number of microseconds needed to send the answer", getSendLatency, StatType::gauge);
494 S.declare("timedout-packets", "Number of packets which weren't answered within timeout set");
495 S.declare("security-status", "Security status based on regular polling", StatType::gauge);
496 S.declare(
497 "xfr-queue", "Size of the queue of zones to be XFRd", [](const string&) { return Communicator.getSuckRequestsWaiting(); }, StatType::gauge);
498 S.declareDNSNameQTypeRing("queries", "UDP Queries Received");
499 S.declareDNSNameQTypeRing("nxdomain-queries", "Queries for nonexistent records within existent zones");
500 S.declareDNSNameQTypeRing("noerror-queries", "Queries for existing records, but for type we don't have");
501 S.declareDNSNameQTypeRing("servfail-queries", "Queries that could not be answered due to backend errors");
502 S.declareDNSNameQTypeRing("unauth-queries", "Queries for zones that we are not authoritative for");
503 S.declareRing("logmessages", "Log Messages");
504 S.declareComboRing("remotes", "Remote server IP addresses");
505 S.declareComboRing("remotes-unauth", "Remote hosts querying zones for which we are not auth");
506 S.declareComboRing("remotes-corrupt", "Remote hosts sending corrupt packets");
507 }
508
509 static int isGuarded(char** argv)
510 {
511 char* p = strstr(argv[0], "-instance");
512
513 return !!p;
514 }
515
516 static void sendout(std::unique_ptr<DNSPacket>& a, int start)
517 {
518 if (!a)
519 return;
520
521 try {
522 int diff = a->d_dt.udiffNoReset();
523 backend_latency = 0.999 * backend_latency + 0.001 * std::max(diff - start, 0);
524 start = diff;
525
526 s_udpNameserver->send(*a);
527
528 diff = a->d_dt.udiff();
529 send_latency = 0.999 * send_latency + 0.001 * std::max(diff - start, 0);
530
531 avg_latency = 0.999 * avg_latency + 0.001 * std::max(diff, 0);
532 }
533 catch (const std::exception& e) {
534 g_log << Logger::Error << "Caught unhandled exception while sending a response: " << e.what() << endl;
535 }
536 }
537
538 //! The qthread receives questions over the internet via the Nameserver class, and hands them to the Distributor for further processing
539 static void qthread(unsigned int num)
540 try {
541 setThreadName("pdns/receiver");
542
543 s_distributors[num] = DNSDistributor::Create(::arg().asNum("distributor-threads", 1));
544 DNSDistributor* distributor = s_distributors[num]; // the big dispatcher!
545 DNSPacket question(true);
546 DNSPacket cached(false);
547
548 AtomicCounter& numreceived = *S.getPointer("udp-queries");
549 AtomicCounter& numreceiveddo = *S.getPointer("udp-do-queries");
550 AtomicCounter& numreceivedcookie = *S.getPointer("udp-cookie-queries");
551
552 AtomicCounter& numreceived4 = *S.getPointer("udp4-queries");
553
554 AtomicCounter& numreceived6 = *S.getPointer("udp6-queries");
555 AtomicCounter& overloadDrops = *S.getPointer("overload-drops");
556
557 int diff, start;
558 bool logDNSQueries = ::arg().mustDo("log-dns-queries");
559 shared_ptr<UDPNameserver> NS;
560 std::string buffer;
561 ComboAddress accountremote;
562
563 // If we have SO_REUSEPORT then create a new port for all receiver threads
564 // other than the first one.
565 if (s_udpNameserver->canReusePort()) {
566 NS = s_udpReceivers[num];
567 if (NS == nullptr) {
568 NS = s_udpNameserver;
569 }
570 }
571 else {
572 NS = s_udpNameserver;
573 }
574
575 for (;;) {
576 try {
577 if (g_proxyProtocolACL.empty()) {
578 buffer.resize(DNSPacket::s_udpTruncationThreshold);
579 }
580 else {
581 buffer.resize(DNSPacket::s_udpTruncationThreshold + g_proxyProtocolMaximumSize);
582 }
583
584 if (!NS->receive(question, buffer)) { // receive a packet inline
585 continue; // packet was broken, try again
586 }
587
588 diff = question.d_dt.udiffNoReset();
589 receive_latency = 0.999 * receive_latency + 0.001 * std::max(diff, 0);
590
591 numreceived++;
592
593 accountremote = question.d_remote;
594 if (question.d_inner_remote)
595 accountremote = *question.d_inner_remote;
596
597 if (accountremote.sin4.sin_family == AF_INET)
598 numreceived4++;
599 else
600 numreceived6++;
601
602 if (question.d_dnssecOk)
603 numreceiveddo++;
604
605 if (question.hasEDNSCookie())
606 numreceivedcookie++;
607
608 if (question.d.qr)
609 continue;
610
611 S.ringAccount("queries", question.qdomain, question.qtype);
612 S.ringAccount("remotes", question.getInnerRemote());
613 if (logDNSQueries) {
614 g_log << Logger::Notice << "Remote " << question.getRemoteString() << " wants '" << question.qdomain << "|" << question.qtype << "', do = " << question.d_dnssecOk << ", bufsize = " << question.getMaxReplyLen();
615 if (question.d_ednsRawPacketSizeLimit > 0 && question.getMaxReplyLen() != (unsigned int)question.d_ednsRawPacketSizeLimit)
616 g_log << " (" << question.d_ednsRawPacketSizeLimit << ")";
617 }
618
619 if (PC.enabled() && (question.d.opcode != Opcode::Notify && question.d.opcode != Opcode::Update) && question.couldBeCached()) {
620 start = diff;
621 bool haveSomething = PC.get(question, cached); // does the PacketCache recognize this question?
622 if (haveSomething) {
623 if (logDNSQueries)
624 g_log << ": packetcache HIT" << endl;
625 cached.setRemote(&question.d_remote); // inlined
626 cached.d_inner_remote = question.d_inner_remote;
627 cached.setSocket(question.getSocket()); // inlined
628 cached.d_anyLocal = question.d_anyLocal;
629 cached.setMaxReplyLen(question.getMaxReplyLen());
630 cached.d.rd = question.d.rd; // copy in recursion desired bit
631 cached.d.id = question.d.id;
632 cached.commitD(); // commit d to the packet inlined
633
634 diff = question.d_dt.udiffNoReset();
635 cache_latency = 0.999 * cache_latency + 0.001 * std::max(diff - start, 0);
636 start = diff;
637
638 NS->send(cached); // answer it then inlined
639
640 diff = question.d_dt.udiff();
641 send_latency = 0.999 * send_latency + 0.001 * std::max(diff - start, 0);
642 avg_latency = 0.999 * avg_latency + 0.001 * std::max(diff, 0); // 'EWMA'
643 continue;
644 }
645 diff = question.d_dt.udiffNoReset();
646 cache_latency = 0.999 * cache_latency + 0.001 * std::max(diff - start, 0);
647 }
648
649 if (distributor->isOverloaded()) {
650 if (logDNSQueries)
651 g_log << ": Dropped query, backends are overloaded" << endl;
652 overloadDrops++;
653 continue;
654 }
655
656 if (logDNSQueries) {
657 if (PC.enabled()) {
658 g_log << ": packetcache MISS" << endl;
659 }
660 else {
661 g_log << endl;
662 }
663 }
664
665 try {
666 distributor->question(question, &sendout); // otherwise, give to the distributor
667 }
668 catch (DistributorFatal& df) { // when this happens, we have leaked loads of memory. Bailing out time.
669 _exit(1);
670 }
671 }
672 catch (const std::exception& e) {
673 g_log << Logger::Error << "Caught unhandled exception in question thread: " << e.what() << endl;
674 }
675 }
676 }
677 catch (PDNSException& pe) {
678 g_log << Logger::Error << "Fatal error in question thread: " << pe.reason << endl;
679 _exit(1);
680 }
681
682 static void dummyThread()
683 {
684 }
685
686 static void triggerLoadOfLibraries()
687 {
688 std::thread dummy(dummyThread);
689 dummy.join();
690 }
691
692 static void mainthread()
693 {
694 gid_t newgid = 0;
695 if (!::arg()["setgid"].empty())
696 newgid = strToGID(::arg()["setgid"]);
697 uid_t newuid = 0;
698 if (!::arg()["setuid"].empty())
699 newuid = strToUID(::arg()["setuid"]);
700
701 g_anyToTcp = ::arg().mustDo("any-to-tcp");
702 g_8bitDNS = ::arg().mustDo("8bit-dns");
703 #ifdef HAVE_LUA_RECORDS
704 g_doLuaRecord = ::arg().mustDo("enable-lua-records");
705 g_LuaRecordSharedState = (::arg()["enable-lua-records"] == "shared");
706 g_luaRecordExecLimit = ::arg().asNum("lua-records-exec-limit");
707 g_luaHealthChecksInterval = ::arg().asNum("lua-health-checks-interval");
708 g_luaConsistentHashesExpireDelay = ::arg().asNum("lua-consistent-hashes-expire-delay");
709 g_luaConsistentHashesCleanupInterval = ::arg().asNum("lua-consistent-hashes-cleanup-interval");
710 g_luaHealthChecksExpireDelay = ::arg().asNum("lua-health-checks-expire-delay");
711 #endif
712 #ifdef ENABLE_GSS_TSIG
713 g_doGssTSIG = ::arg().mustDo("enable-gss-tsig");
714 #endif
715
716 DNSPacket::s_udpTruncationThreshold = std::max(512, ::arg().asNum("udp-truncation-threshold"));
717 DNSPacket::s_doEDNSSubnetProcessing = ::arg().mustDo("edns-subnet-processing");
718 PacketHandler::s_SVCAutohints = ::arg().mustDo("svc-autohints");
719
720 g_proxyProtocolACL.toMasks(::arg()["proxy-protocol-from"]);
721 g_proxyProtocolMaximumSize = ::arg().asNum("proxy-protocol-maximum-size");
722
723 if (::arg()["edns-cookie-secret"].size() != 0) {
724 // User wants cookie processing
725 #ifdef HAVE_CRYPTO_SHORTHASH // we can do siphash-based cookies
726 DNSPacket::s_doEDNSCookieProcessing = true;
727 try {
728 if (::arg()["edns-cookie-secret"].size() != EDNSCookiesOpt::EDNSCookieSecretSize) {
729 throw std::range_error("wrong size (" + std::to_string(::arg()["edns-cookie-secret"].size()) + "), must be " + std::to_string(EDNSCookiesOpt::EDNSCookieSecretSize));
730 }
731 DNSPacket::s_EDNSCookieKey = makeBytesFromHex(::arg()["edns-cookie-secret"]);
732 }
733 catch (const std::range_error& e) {
734 g_log << Logger::Error << "edns-cookie-secret invalid: " << e.what() << endl;
735 exit(1);
736 }
737 #else
738 g_log << Logger::Error << "Support for EDNS Cookies is not available because of missing cryptographic functions (libsodium support should be enabled, with the crypto_shorthash() function available)" << endl;
739 exit(1);
740 #endif
741 }
742
743 PC.setTTL(::arg().asNum("cache-ttl"));
744 PC.setMaxEntries(::arg().asNum("max-packet-cache-entries"));
745 QC.setMaxEntries(::arg().asNum("max-cache-entries"));
746 DNSSECKeeper::setMaxEntries(::arg().asNum("max-cache-entries"));
747
748 if (!PC.enabled() && ::arg().mustDo("log-dns-queries")) {
749 g_log << Logger::Warning << "Packet cache disabled, logging queries without HIT/MISS" << endl;
750 }
751 if (::arg()["outgoing-axfr-expand-alias"] == "ignore-errors") {
752 g_log << Logger::Error << "Ignoring ALIAS resolve failures on outgoing AXFR transfers, see option \"outgoing-axfr-expand-alias\"" << endl;
753 }
754
755 stubParseResolveConf();
756
757 if (!::arg()["chroot"].empty()) {
758 #ifdef HAVE_SYSTEMD
759 char* ns;
760 ns = getenv("NOTIFY_SOCKET");
761 if (ns != nullptr) {
762 g_log << Logger::Error << "Unable to chroot when running from systemd. Please disable chroot= or set the 'Type' for this service to 'simple'" << endl;
763 exit(1);
764 }
765 #endif
766 triggerLoadOfLibraries();
767 if (::arg().mustDo("primary") || ::arg().mustDo("secondary"))
768 gethostbyname("a.root-servers.net"); // this forces all lookup libraries to be loaded
769 Utility::dropGroupPrivs(newuid, newgid);
770 if (chroot(::arg()["chroot"].c_str()) < 0 || chdir("/") < 0) {
771 g_log << Logger::Error << "Unable to chroot to '" + ::arg()["chroot"] + "': " << stringerror() << ", exiting" << endl;
772 exit(1);
773 }
774 else
775 g_log << Logger::Error << "Chrooted to '" << ::arg()["chroot"] << "'" << endl;
776 }
777 else {
778 Utility::dropGroupPrivs(newuid, newgid);
779 }
780
781 AuthWebServer webserver;
782 Utility::dropUserPrivs(newuid);
783
784 if (::arg().mustDo("resolver")) {
785 DP = std::make_unique<DNSProxy>(::arg()["resolver"]);
786 DP->go();
787 }
788
789 try {
790 doSecPoll(true);
791 }
792 catch (...) {
793 }
794
795 {
796 // Some sanity checking on default key settings
797 bool hadKeyError = false;
798 int kskAlgo{0}, zskAlgo{0};
799 for (const string algotype : {"ksk", "zsk"}) {
800 int algo, size;
801 if (::arg()["default-" + algotype + "-algorithm"].empty())
802 continue;
803 algo = DNSSECKeeper::shorthand2algorithm(::arg()["default-" + algotype + "-algorithm"]);
804 size = ::arg().asNum("default-" + algotype + "-size");
805 if (algo == -1) {
806 g_log << Logger::Error << "Error: default-" << algotype << "-algorithm set to unknown algorithm: " << ::arg()["default-" + algotype + "-algorithm"] << endl;
807 hadKeyError = true;
808 }
809 else if (algo <= 10 && size == 0) {
810 g_log << Logger::Error << "Error: default-" << algotype << "-algorithm is set to an algorithm (" << ::arg()["default-" + algotype + "-algorithm"] << ") that requires a non-zero default-" << algotype << "-size!" << endl;
811 hadKeyError = true;
812 }
813 if (algotype == "ksk") {
814 kskAlgo = algo;
815 }
816 else {
817 zskAlgo = algo;
818 }
819 }
820 if (hadKeyError) {
821 exit(1);
822 }
823 if (kskAlgo == 0 && zskAlgo != 0) {
824 g_log << Logger::Error << "Error: default-zsk-algorithm is set, but default-ksk-algorithm is not set." << endl;
825 exit(1);
826 }
827 if (zskAlgo != 0 && zskAlgo != kskAlgo) {
828 g_log << Logger::Error << "Error: default-zsk-algorithm (" << ::arg()["default-zsk-algorithm"] << "), when set, can not be different from default-ksk-algorithm (" << ::arg()["default-ksk-algorithm"] << ")." << endl;
829 exit(1);
830 }
831 }
832
833 pdns::parseQueryLocalAddress(::arg()["query-local-address"]);
834
835 pdns::parseTrustedNotificationProxy(::arg()["trusted-notification-proxy"]);
836
837 UeberBackend::go();
838
839 // Setup the zone cache
840 g_zoneCache.setRefreshInterval(::arg().asNum("zone-cache-refresh-interval"));
841 try {
842 UeberBackend B;
843 B.updateZoneCache();
844 }
845 catch (PDNSException& e) {
846 g_log << Logger::Error << "PDNSException while filling the zone cache: " << e.reason << endl;
847 exit(1);
848 }
849 catch (std::exception& e) {
850 g_log << Logger::Error << "STL Exception while filling the zone cache: " << e.what() << endl;
851 exit(1);
852 }
853
854 // NOW SAFE TO CREATE THREADS!
855 s_dynListener->go();
856
857 if (::arg().mustDo("webserver") || ::arg().mustDo("api")) {
858 webserver.go(S);
859 }
860
861 if (::arg().mustDo("primary") || ::arg().mustDo("secondary") || !::arg()["forward-notify"].empty())
862 Communicator.go();
863
864 s_tcpNameserver->go(); // tcp nameserver launch
865
866 unsigned int max_rthreads = ::arg().asNum("receiver-threads", 1);
867 s_distributors.resize(max_rthreads);
868 for (unsigned int n = 0; n < max_rthreads; ++n) {
869 std::thread t(qthread, n);
870 t.detach();
871 }
872
873 std::thread carbonThread(carbonDumpThread); // runs even w/o carbon, might change @ runtime
874
875 #ifdef HAVE_SYSTEMD
876 /* If we are here, notify systemd that we are ay-ok! This might have some
877 * timing issues with the backend-threads. e.g. if the initial MySQL connection
878 * is slow and times out (leading to process termination through the backend)
879 * We probably have told systemd already that we have started correctly.
880 */
881 sd_notify(0, "READY=1");
882 #endif
883
884 const uint32_t secpollInterval = 1800;
885 uint32_t secpollSince = 0;
886 uint32_t zoneCacheUpdateSince = 0;
887 for (;;) {
888 const uint32_t sleeptime = g_zoneCache.getRefreshInterval() == 0 ? secpollInterval : std::min(secpollInterval, g_zoneCache.getRefreshInterval());
889 sleep(sleeptime); // if any signals arrive, we might run more often than expected.
890
891 zoneCacheUpdateSince += sleeptime;
892 if (zoneCacheUpdateSince >= g_zoneCache.getRefreshInterval()) {
893 try {
894 UeberBackend B;
895 B.updateZoneCache();
896 zoneCacheUpdateSince = 0;
897 }
898 catch (PDNSException& e) {
899 g_log << Logger::Error << "PDNSException while updating zone cache: " << e.reason << endl;
900 }
901 catch (std::exception& e) {
902 g_log << Logger::Error << "STL Exception while updating zone cache: " << e.what() << endl;
903 }
904 }
905
906 secpollSince += sleeptime;
907 if (secpollSince >= secpollInterval) {
908 secpollSince = 0;
909 try {
910 doSecPoll(false);
911 }
912 catch (...) {
913 }
914 }
915 }
916
917 g_log << Logger::Error << "Mainthread exiting - should never happen" << endl;
918 }
919
920 static void daemonize()
921 {
922 if (fork())
923 exit(0); // bye bye
924
925 setsid();
926
927 int i = open("/dev/null", O_RDWR); /* open stdin */
928 if (i < 0)
929 g_log << Logger::Critical << "Unable to open /dev/null: " << stringerror() << endl;
930 else {
931 dup2(i, 0); /* stdin */
932 dup2(i, 1); /* stderr */
933 dup2(i, 2); /* stderr */
934 close(i);
935 }
936 }
937
938 static int cpid;
939 static void takedown(int /* i */)
940 {
941 if (cpid) {
942 g_log << Logger::Error << "Guardian is killed, taking down children with us" << endl;
943 kill(cpid, SIGKILL);
944 exit(0);
945 }
946 }
947
948 static void writePid()
949 {
950 if (!::arg().mustDo("write-pid"))
951 return;
952
953 string fname = ::arg()["socket-dir"];
954 if (::arg()["socket-dir"].empty()) {
955 if (::arg()["chroot"].empty())
956 fname = std::string(LOCALSTATEDIR) + "/pdns";
957 else
958 fname = ::arg()["chroot"] + "/";
959 }
960 else if (!::arg()["socket-dir"].empty() && !::arg()["chroot"].empty()) {
961 fname = ::arg()["chroot"] + ::arg()["socket-dir"];
962 }
963
964 fname += +"/" + g_programname + ".pid";
965 ofstream of(fname.c_str());
966 if (of)
967 of << getpid() << endl;
968 else
969 g_log << Logger::Error << "Writing pid for " << getpid() << " to " << fname << " failed: " << stringerror() << endl;
970 }
971
972 static int g_fd1[2], g_fd2[2];
973 static FILE* g_fp;
974 static std::mutex g_guardian_lock;
975
976 // The next two methods are not in dynhandler.cc because they use a few items declared in this file.
977 static string DLCycleHandler(const vector<string>& /* parts */, pid_t /* ppid */)
978 {
979 kill(cpid, SIGKILL); // why?
980 kill(cpid, SIGKILL); // why?
981 sleep(1);
982 return "ok";
983 }
984
985 static string DLRestHandler(const vector<string>& parts, pid_t /* ppid */)
986 {
987 string line;
988
989 for (vector<string>::const_iterator i = parts.begin(); i != parts.end(); ++i) {
990 if (i != parts.begin())
991 line.append(1, ' ');
992 line.append(*i);
993 }
994 line.append(1, '\n');
995
996 std::lock_guard<std::mutex> l(g_guardian_lock);
997
998 try {
999 writen2(g_fd1[1], line.c_str(), line.size() + 1);
1000 }
1001 catch (PDNSException& ae) {
1002 return "Error communicating with instance: " + ae.reason;
1003 }
1004 char mesg[512];
1005 string response;
1006 while (fgets(mesg, sizeof(mesg), g_fp)) {
1007 if (*mesg == '\0')
1008 break;
1009 response += mesg;
1010 }
1011 boost::trim_right(response);
1012 return response;
1013 }
1014
1015 static int guardian(int argc, char** argv)
1016 {
1017 if (isGuarded(argv))
1018 return 0;
1019
1020 int infd = 0, outfd = 1;
1021
1022 DynListener dlg(g_programname);
1023 dlg.registerFunc("QUIT", &DLQuitHandler, "quit daemon");
1024 dlg.registerFunc("CYCLE", &DLCycleHandler, "restart instance");
1025 dlg.registerFunc("PING", &DLPingHandler, "ping guardian");
1026 dlg.registerFunc("STATUS", &DLStatusHandler, "get instance status from guardian");
1027 dlg.registerRestFunc(&DLRestHandler);
1028 dlg.go();
1029 string progname = argv[0];
1030
1031 bool first = true;
1032 cpid = 0;
1033
1034 g_guardian_lock.lock();
1035
1036 for (;;) {
1037 int pid;
1038 setStatus("Launching child");
1039
1040 if (pipe(g_fd1) < 0 || pipe(g_fd2) < 0) {
1041 g_log << Logger::Critical << "Unable to open pipe for coprocess: " << stringerror() << endl;
1042 exit(1);
1043 }
1044
1045 if (!(g_fp = fdopen(g_fd2[0], "r"))) {
1046 g_log << Logger::Critical << "Unable to associate a file pointer with pipe: " << stringerror() << endl;
1047 exit(1);
1048 }
1049 setbuf(g_fp, nullptr); // no buffering please, confuses select
1050
1051 if (!(pid = fork())) { // child
1052 signal(SIGTERM, SIG_DFL);
1053
1054 signal(SIGHUP, SIG_DFL);
1055 signal(SIGUSR1, SIG_DFL);
1056 signal(SIGUSR2, SIG_DFL);
1057
1058 char** const newargv = new char*[argc + 2];
1059 int n;
1060
1061 if (::arg()["config-name"] != "") {
1062 progname += "-" + ::arg()["config-name"];
1063 g_log << Logger::Error << "Virtual configuration name: " << ::arg()["config-name"] << endl;
1064 }
1065
1066 newargv[0] = strdup(const_cast<char*>((progname + "-instance").c_str()));
1067 for (n = 1; n < argc; n++) {
1068 newargv[n] = argv[n];
1069 }
1070 newargv[n] = nullptr;
1071
1072 g_log << Logger::Error << "Guardian is launching an instance" << endl;
1073 close(g_fd1[1]);
1074 fclose(g_fp); // this closes g_fd2[0] for us
1075
1076 if (g_fd1[0] != infd) {
1077 dup2(g_fd1[0], infd);
1078 close(g_fd1[0]);
1079 }
1080
1081 if (g_fd2[1] != outfd) {
1082 dup2(g_fd2[1], outfd);
1083 close(g_fd2[1]);
1084 }
1085 if (execvp(argv[0], newargv) < 0) {
1086 g_log << Logger::Error << "Unable to execvp '" << argv[0] << "': " << stringerror() << endl;
1087 char** p = newargv;
1088 while (*p)
1089 g_log << Logger::Error << *p++ << endl;
1090
1091 exit(1);
1092 }
1093 g_log << Logger::Error << "execvp returned!!" << endl;
1094 // never reached
1095 }
1096 else if (pid > 0) { // parent
1097 close(g_fd1[0]);
1098 close(g_fd2[1]);
1099
1100 if (first) {
1101 first = false;
1102 signal(SIGTERM, takedown);
1103
1104 signal(SIGHUP, SIG_IGN);
1105 signal(SIGUSR1, SIG_IGN);
1106 signal(SIGUSR2, SIG_IGN);
1107
1108 writePid();
1109 }
1110 g_guardian_lock.unlock();
1111 int status;
1112 cpid = pid;
1113 for (;;) {
1114 int ret = waitpid(pid, &status, WNOHANG);
1115
1116 if (ret < 0) {
1117 g_log << Logger::Error << "In guardian loop, waitpid returned error: " << stringerror() << endl;
1118 g_log << Logger::Error << "Dying" << endl;
1119 exit(1);
1120 }
1121 else if (ret) // something exited
1122 break;
1123 else { // child is alive
1124 // execute some kind of ping here
1125 if (DLQuitPlease())
1126 takedown(1); // needs a parameter..
1127 setStatus("Child running on pid " + std::to_string(pid));
1128 sleep(1);
1129 }
1130 }
1131
1132 g_guardian_lock.lock();
1133 close(g_fd1[1]);
1134 fclose(g_fp);
1135 g_fp = nullptr;
1136
1137 if (WIFEXITED(status)) {
1138 int ret = WEXITSTATUS(status);
1139
1140 if (ret == 99) {
1141 g_log << Logger::Error << "Child requested a stop, exiting" << endl;
1142 exit(1);
1143 }
1144 setStatus("Child died with code " + std::to_string(ret));
1145 g_log << Logger::Error << "Our pdns instance exited with code " << ret << ", respawning" << endl;
1146
1147 sleep(1);
1148 continue;
1149 }
1150 if (WIFSIGNALED(status)) {
1151 int sig = WTERMSIG(status);
1152 setStatus("Child died because of signal " + std::to_string(sig));
1153 g_log << Logger::Error << "Our pdns instance (" << pid << ") exited after signal " << sig << endl;
1154 #ifdef WCOREDUMP
1155 if (WCOREDUMP(status))
1156 g_log << Logger::Error << "Dumped core" << endl;
1157 #endif
1158
1159 g_log << Logger::Error << "Respawning" << endl;
1160 sleep(1);
1161 continue;
1162 }
1163 g_log << Logger::Error << "No clue what happened! Respawning" << endl;
1164 }
1165 else {
1166 g_log << Logger::Error << "Unable to fork: " << stringerror() << endl;
1167 exit(1);
1168 }
1169 }
1170 }
1171
1172 #if defined(__GLIBC__) && !defined(__UCLIBC__)
1173 #include <execinfo.h>
1174 static void tbhandler(int num)
1175 {
1176 g_log << Logger::Critical << "Got a signal " << num << ", attempting to print trace: " << endl;
1177 void* array[20]; // only care about last 17 functions (3 taken with tracing support)
1178 size_t size;
1179 char** strings;
1180 size_t i;
1181
1182 size = backtrace(array, 20);
1183 strings = backtrace_symbols(array, size); // Need -rdynamic gcc (linker) flag for this to work
1184
1185 for (i = 0; i < size; i++) // skip useless functions
1186 g_log << Logger::Error << strings[i] << endl;
1187
1188 signal(SIGABRT, SIG_DFL);
1189 abort(); // hopefully will give core
1190 }
1191 #endif
1192
1193 #ifdef COVERAGE
1194 static void sigTermHandler([[maybe_unused]] int signal)
1195 {
1196 pdns::coverage::dumpCoverageData();
1197 _exit(EXIT_SUCCESS);
1198 }
1199 #endif /* COVERAGE */
1200
1201 //! The main function of pdns, the pdns process
1202 int main(int argc, char** argv)
1203 {
1204 versionSetProduct(ProductAuthoritative);
1205 reportAllTypes(); // init MOADNSParser
1206
1207 g_programname = "pdns";
1208 g_starttime = time(nullptr);
1209
1210 #if defined(__GLIBC__) && !defined(__UCLIBC__)
1211 signal(SIGSEGV, tbhandler);
1212 signal(SIGFPE, tbhandler);
1213 signal(SIGABRT, tbhandler);
1214 signal(SIGILL, tbhandler);
1215 #endif
1216
1217 std::ios_base::sync_with_stdio(false);
1218
1219 g_log.toConsole(Logger::Warning);
1220 try {
1221 declareArguments();
1222
1223 ::arg().laxParse(argc, argv); // do a lax parse
1224
1225 if (::arg().mustDo("version")) {
1226 showProductVersion();
1227 showBuildConfiguration();
1228 return 0;
1229 }
1230
1231 if (::arg()["config-name"] != "")
1232 g_programname += "-" + ::arg()["config-name"];
1233
1234 g_log.setName(g_programname);
1235
1236 string configname = ::arg()["config-dir"] + "/" + g_programname + ".conf";
1237 cleanSlashes(configname);
1238
1239 if (::arg()["config"] != "default" && !::arg().mustDo("no-config")) // "config" == print a configuration file
1240 ::arg().laxFile(configname.c_str());
1241
1242 ::arg().laxParse(argc, argv); // reparse so the commandline still wins
1243 if (!::arg()["logging-facility"].empty()) {
1244 int val = logFacilityToLOG(::arg().asNum("logging-facility"));
1245 if (val >= 0)
1246 g_log.setFacility(val);
1247 else
1248 g_log << Logger::Error << "Unknown logging facility " << ::arg().asNum("logging-facility") << endl;
1249 }
1250
1251 if (!::arg().isEmpty("domain-metadata-cache-ttl"))
1252 ::arg().set("zone-metadata-cache-ttl") = ::arg()["domain-metadata-cache-ttl"];
1253
1254 // this mirroring back is on purpose, so that config dumps reflect the actual setting on both names
1255 ::arg().set("domain-metadata-cache-ttl") = ::arg()["zone-metadata-cache-ttl"];
1256
1257 g_log.setLoglevel((Logger::Urgency)(::arg().asNum("loglevel")));
1258 g_log.setPrefixed(::arg().mustDo("loglevel-show"));
1259 g_log.disableSyslog(::arg().mustDo("disable-syslog"));
1260 g_log.setTimestamps(::arg().mustDo("log-timestamp"));
1261 g_log.toConsole((Logger::Urgency)(::arg().asNum("loglevel")));
1262
1263 if (::arg().mustDo("help") || ::arg().mustDo("config")) {
1264 ::arg().set("daemon") = "no";
1265 ::arg().set("guardian") = "no";
1266 }
1267
1268 if (::arg().mustDo("guardian") && !isGuarded(argv)) {
1269 if (::arg().mustDo("daemon")) {
1270 g_log.toConsole(Logger::Critical);
1271 daemonize();
1272 }
1273 guardian(argc, argv);
1274 // never get here, guardian will reinvoke process
1275 cerr << "Um, we did get here!" << endl;
1276 }
1277
1278 #ifdef COVERAGE
1279 if (!::arg().mustDo("guardian") && !::arg().mustDo("daemon")) {
1280 signal(SIGTERM, sigTermHandler);
1281 }
1282 #endif
1283
1284 // we really need to do work - either standalone or as an instance
1285
1286 #if defined(__GLIBC__) && !defined(__UCLIBC__)
1287 if (!::arg().mustDo("traceback-handler")) {
1288 g_log << Logger::Warning << "Disabling traceback handler" << endl;
1289 signal(SIGSEGV, SIG_DFL);
1290 signal(SIGFPE, SIG_DFL);
1291 signal(SIGABRT, SIG_DFL);
1292 signal(SIGILL, SIG_DFL);
1293 }
1294 #endif
1295
1296 #ifdef HAVE_LIBSODIUM
1297 if (sodium_init() == -1) {
1298 cerr << "Unable to initialize sodium crypto library" << endl;
1299 exit(99);
1300 }
1301 #endif
1302
1303 openssl_thread_setup();
1304 openssl_seed();
1305
1306 #ifdef HAVE_LUA_RECORDS
1307 MiniCurl::init();
1308 #endif /* HAVE_LUA_RECORDS */
1309
1310 if (!::arg()["load-modules"].empty()) {
1311 vector<string> modules;
1312
1313 stringtok(modules, ::arg()["load-modules"], ", ");
1314 if (!UeberBackend::loadModules(modules, ::arg()["module-dir"])) {
1315 exit(1);
1316 }
1317 }
1318
1319 BackendMakers().launch(::arg()["launch"]); // vrooooom!
1320
1321 if (!::arg().getCommands().empty()) {
1322 cerr << "Fatal: non-option";
1323 if (::arg().getCommands().size() > 1) {
1324 cerr << "s";
1325 }
1326 cerr << " (";
1327 bool first = true;
1328 for (const auto& c : ::arg().getCommands()) {
1329 if (!first) {
1330 cerr << ", ";
1331 }
1332 first = false;
1333 cerr << c;
1334 }
1335 cerr << ") on the command line, perhaps a '--setting=123' statement missed the '='?" << endl;
1336 exit(99);
1337 }
1338
1339 if (::arg().mustDo("help")) {
1340 cout << "syntax:" << endl
1341 << endl;
1342 cout << ::arg().helpstring(::arg()["help"]) << endl;
1343 exit(0);
1344 }
1345
1346 if (::arg().mustDo("config")) {
1347 string config = ::arg()["config"];
1348 if (config == "default") {
1349 cout << ::arg().configstring(false, true);
1350 }
1351 else if (config == "diff") {
1352 cout << ::arg().configstring(true, false);
1353 }
1354 else if (config == "check") {
1355 try {
1356 if (!::arg().mustDo("no-config"))
1357 ::arg().file(configname.c_str());
1358 ::arg().parse(argc, argv);
1359 exit(0);
1360 }
1361 catch (const ArgException& A) {
1362 cerr << "Fatal error: " << A.reason << endl;
1363 exit(1);
1364 }
1365 }
1366 else {
1367 cout << ::arg().configstring(true, true);
1368 }
1369 exit(0);
1370 }
1371
1372 if (::arg().mustDo("list-modules")) {
1373 auto modules = BackendMakers().getModules();
1374 cout << "Modules available:" << endl;
1375 for (const auto& m : modules)
1376 cout << m << endl;
1377
1378 _exit(99);
1379 }
1380
1381 if (!::arg().asNum("local-port")) {
1382 g_log << Logger::Error << "Unable to launch, binding to no port or port 0 makes no sense" << endl;
1383 exit(99); // this isn't going to fix itself either
1384 }
1385 if (!BackendMakers().numLauncheable()) {
1386 g_log << Logger::Error << "Unable to launch, no backends configured for querying" << endl;
1387 exit(99); // this isn't going to fix itself either
1388 }
1389 if (::arg().mustDo("daemon")) {
1390 g_log.toConsole(Logger::None);
1391 if (!isGuarded(argv))
1392 daemonize();
1393 }
1394
1395 if (isGuarded(argv)) {
1396 g_log << Logger::Warning << "This is a guarded instance of pdns" << endl;
1397 s_dynListener = std::make_unique<DynListener>(); // listens on stdin
1398 }
1399 else {
1400 g_log << Logger::Warning << "This is a standalone pdns" << endl;
1401
1402 if (::arg().mustDo("control-console"))
1403 s_dynListener = std::make_unique<DynListener>();
1404 else
1405 s_dynListener = std::make_unique<DynListener>(g_programname);
1406
1407 writePid();
1408 }
1409 DynListener::registerFunc("SHOW", &DLShowHandler, "show a specific statistic or * to get a list", "<statistic>");
1410 DynListener::registerFunc("RPING", &DLPingHandler, "ping instance");
1411 DynListener::registerFunc("QUIT", &DLRQuitHandler, "quit daemon");
1412 DynListener::registerFunc("UPTIME", &DLUptimeHandler, "get instance uptime");
1413 DynListener::registerFunc("NOTIFY-HOST", &DLNotifyHostHandler, "notify host for specific zone", "<zone> <host>");
1414 DynListener::registerFunc("NOTIFY", &DLNotifyHandler, "queue a notification", "<zone>");
1415 DynListener::registerFunc("RELOAD", &DLReloadHandler, "reload all zones");
1416 DynListener::registerFunc("REDISCOVER", &DLRediscoverHandler, "discover any new zones");
1417 DynListener::registerFunc("VERSION", &DLVersionHandler, "get instance version");
1418 DynListener::registerFunc("PURGE", &DLPurgeHandler, "purge entries from packet cache", "[<record>]");
1419 DynListener::registerFunc("CCOUNTS", &DLCCHandler, "get cache statistics");
1420 DynListener::registerFunc("QTYPES", &DLQTypesHandler, "get QType statistics");
1421 DynListener::registerFunc("RESPSIZES", &DLRSizesHandler, "get histogram of response sizes");
1422 DynListener::registerFunc("REMOTES", &DLRemotesHandler, "get top remotes");
1423 DynListener::registerFunc("SET", &DLSettingsHandler, "set config variables", "<var> <value>");
1424 DynListener::registerFunc("RETRIEVE", &DLNotifyRetrieveHandler, "retrieve secondary zone", "<zone> [<ip>]");
1425 DynListener::registerFunc("CURRENT-CONFIG", &DLCurrentConfigHandler, "retrieve the current configuration", "[diff]");
1426 DynListener::registerFunc("LIST-ZONES", &DLListZones, "show list of zones", "[primary|secondary|native|consumer|producer]");
1427 DynListener::registerFunc("TOKEN-LOGIN", &DLTokenLogin, "Login to a PKCS#11 token", "<module> <slot> <pin>");
1428 DynListener::registerFunc("XFR-QUEUE", &DLSuckRequests, "Get all requests for XFR in queue");
1429
1430 if (!::arg()["tcp-control-address"].empty()) {
1431 DynListener* dlTCP = new DynListener(ComboAddress(::arg()["tcp-control-address"], ::arg().asNum("tcp-control-port")));
1432 dlTCP->go();
1433 }
1434
1435 // reparse, with error checking
1436 if (!::arg().mustDo("no-config"))
1437 ::arg().file(configname.c_str());
1438 ::arg().parse(argc, argv);
1439
1440 if (::arg()["server-id"].empty()) {
1441 char tmp[128];
1442 if (gethostname(tmp, sizeof(tmp) - 1) == 0) {
1443 ::arg().set("server-id") = tmp;
1444 }
1445 else {
1446 g_log << Logger::Warning << "Unable to get the hostname, NSID and id.server values will be empty: " << stringerror() << endl;
1447 }
1448 }
1449
1450 s_udpNameserver = std::make_shared<UDPNameserver>(); // this fails when we are not root, throws exception
1451 s_udpReceivers.push_back(s_udpNameserver);
1452
1453 size_t rthreads = ::arg().asNum("receiver-threads", 1);
1454 if (rthreads > 1 && s_udpNameserver->canReusePort()) {
1455 s_udpReceivers.resize(rthreads);
1456
1457 for (size_t idx = 1; idx < rthreads; idx++) {
1458 try {
1459 s_udpReceivers[idx] = std::make_shared<UDPNameserver>(true);
1460 }
1461 catch (const PDNSException& e) {
1462 g_log << Logger::Error << "Unable to reuse port, falling back to original bind" << endl;
1463 break;
1464 }
1465 }
1466 }
1467
1468 s_tcpNameserver = make_unique<TCPNameserver>();
1469 }
1470 catch (const ArgException& A) {
1471 g_log << Logger::Error << "Fatal error: " << A.reason << endl;
1472 exit(1);
1473 }
1474 catch (const std::exception& e) {
1475 g_log << Logger::Error << "Fatal error: " << e.what() << endl;
1476 exit(1);
1477 }
1478
1479 try {
1480 declareStats();
1481 }
1482 catch (const PDNSException& PE) {
1483 g_log << Logger::Error << "Exiting because: " << PE.reason << endl;
1484 exit(1);
1485 }
1486
1487 try {
1488 auto defaultCatalog = ::arg()["default-catalog-zone"];
1489 if (!defaultCatalog.empty()) {
1490 auto defCatalog = DNSName(defaultCatalog);
1491 }
1492 }
1493 catch (const std::exception& e) {
1494 g_log << Logger::Error << "Invalid value '" << ::arg()["default-catalog-zone"] << "' for default-catalog-zone: " << e.what() << endl;
1495 exit(1);
1496 }
1497 S.blacklist("special-memory-usage");
1498
1499 DLOG(g_log << Logger::Warning << "Verbose logging in effect" << endl);
1500
1501 showProductVersion();
1502
1503 try {
1504 mainthread();
1505 }
1506 catch (const PDNSException& e) {
1507 try {
1508 if (!::arg().mustDo("daemon")) {
1509 cerr << "Exiting because: " << e.reason << endl;
1510 }
1511 }
1512 catch (const ArgException& A) {
1513 }
1514 g_log << Logger::Error << "Exiting because: " << e.reason << endl;
1515 }
1516 catch (const std::exception& e) {
1517 try {
1518 if (!::arg().mustDo("daemon")) {
1519 cerr << "Exiting because of STL error: " << e.what() << endl;
1520 }
1521 }
1522 catch (const ArgException& A) {
1523 }
1524 g_log << Logger::Error << "Exiting because of STL error: " << e.what() << endl;
1525 }
1526 catch (...) {
1527 cerr << "Uncaught exception of unknown type - sorry" << endl;
1528 }
1529
1530 exit(1);
1531 }