]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/auth-main.cc
rec: allow exception to proxy protocal usage for specific listen addresses
[thirdparty/pdns.git] / pdns / auth-main.cc
CommitLineData
12c86877 1/*
12471842
PL
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
8cb70f23 25#include <cstdio>
dc6aa7f5 26#include <csignal>
8cb70f23
CH
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>
e903706d 37#include <sys/resource.h>
8cb70f23
CH
38#include <sys/time.h>
39#include <sys/wait.h>
dc6aa7f5 40#include <cerrno>
8cb70f23
CH
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"
460a6daa 56#include "coverage.hh"
8cb70f23 57#include "secpoll-auth.hh"
f45a622c 58#include "dynhandler.hh"
82ee5aa5 59#include "dnsseckeeper.hh"
519f5484 60#include "threadname.hh"
2211dac9 61#include "misc.hh"
20829585 62#include "query-local-address.hh"
1886a4b3 63#include "trusted-notification-proxy.hh"
8cb70f23 64#include "packetcache.hh"
0a21c8ea 65#include "packethandler.hh"
8cb70f23
CH
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"
fa8fd4d2 87
8cb70f23
CH
88#ifdef HAVE_LUA_RECORDS
89#include "minicurl.hh"
90#endif /* HAVE_LUA_RECORDS */
c2826d2e 91
c509c9fa 92time_t g_starttime;
8cb70f23 93
c509c9fa 94string g_programname = "pdns"; // used in packethandler.cc
ad5f04f1
CH
95
96const char* funnytext = "*****************************************************************************\n"
bcd5ed15
FM
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"
ad5f04f1
CH
103 " the pdns crew - pdns@powerdns.com\n"
104 "*****************************************************************************\n";
b653a73d 105
357f6a75 106bool g_anyToTcp;
fc41a1a6 107bool g_8bitDNS;
8900e2e3 108#ifdef HAVE_LUA_RECORDS
cb6bd1a9 109bool g_doLuaRecord;
af68014f 110int g_luaRecordExecLimit;
a6897a16
CHB
111time_t g_luaHealthChecksInterval{5};
112time_t g_luaHealthChecksExpireDelay{3600};
a6be268f
CHB
113time_t g_luaConsistentHashesExpireDelay{86400};
114time_t g_luaConsistentHashesCleanupInterval{3600};
8900e2e3 115#endif
c113acc3 116#ifdef ENABLE_GSS_TSIG
fd7bbdb7 117bool g_doGssTSIG;
c113acc3 118#endif
ad5f04f1 119typedef Distributor<DNSPacket, DNSPacket, PacketHandler> DNSDistributor;
619e8acc 120
619e8acc 121ArgvMap theArg;
ad5f04f1 122StatBag S; //!< Statistics are gathered across PDNS via the StatBag class S
bf269e28
RG
123AuthPacketCache PC; //!< This is the main PacketCache, shared across all threads
124AuthQueryCache QC;
1f0fb39a 125AuthZoneCache g_zoneCache;
c2826d2e 126std::unique_ptr<DNSProxy> DP{nullptr};
a270fbcb 127static std::unique_ptr<DynListener> s_dynListener{nullptr};
619e8acc 128CommunicatorClass Communicator;
7163e400 129static double avg_latency{0.0}, receive_latency{0.0}, cache_latency{0.0}, backend_latency{0.0}, send_latency{0.0};
6738003e 130static unique_ptr<TCPNameserver> s_tcpNameserver{nullptr};
346872ff 131static vector<DNSDistributor*> s_distributors;
dd81fb3b 132static shared_ptr<UDPNameserver> s_udpNameserver{nullptr};
fcab180d 133static vector<std::shared_ptr<UDPNameserver>> s_udpReceivers;
4172a5b2
PD
134NetmaskGroup g_proxyProtocolACL;
135size_t g_proxyProtocolMaximumSize;
619e8acc 136
ad5f04f1 137ArgvMap& arg()
619e8acc
BH
138{
139 return theArg;
140}
141
8de02315 142static void declareArguments()
619e8acc 143{
ad5f04f1
CH
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"
9a5b0a54 147#ifdef HAVE_SYSTEMD
ad5f04f1
CH
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 }
9a5b0a54 154#else
ad5f04f1
CH
155 )
156 = "";
9a5b0a54 157#endif
ad5f04f1
CH
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";
006dac60 167 ::arg().setSwitch("dnsupdate-require-tsig", "Require TSIG secured DNS updates. Default is no.") = "no";
ad5f04f1
CH
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";
2dc0dd0c 170 ::arg().setSwitch("send-signed-notify", "Send TSIG secured NOTIFY if TSIG key is configured for a zone") = "yes";
ad5f04f1 171 ::arg().set("allow-unsigned-notify", "Allow unsigned notifications for TSIG secured zones") = "yes"; // FIXME: change to 'no' later
ad5f04f1 172 ::arg().set("allow-unsigned-autoprimary", "Allow autoprimaries to create zones without TSIG signed NOTIFY") = "yes";
c02c999b 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";
ad5f04f1
CH
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
c02c999b 184 ::arg().set("retrieval-threads", "Number of AXFR-retrieval threads for secondary operation") = "2";
ad5f04f1
CH
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";
46eec001 199 ::arg().setSwitch("loglevel-show", "Include log level indicator in log output") = "no";
cd77295b 200 ::arg().set("disable-syslog", "Disable logging to syslog, useful when running inside a supervisor that logs stderr") = "no";
ad5f04f1
CH
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";
3af419da 204 ::arg().setSwitch("workaround-11804", "Workaround for issue 11804: send single RR per AXFR chunk") = "no";
ad5f04f1
CH
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";
2dc0dd0c 217 ::arg().set("also-notify", "When notifying a zone, also notify these nameservers") = "";
ad5f04f1 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";
ad5f04f1 219 ::arg().set("xfr-cycle-interval", "Schedule primary/secondary SOA freshness checks once every .. seconds") = "60";
d804bbeb 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";
ad5f04f1
CH
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
ad5f04f1 227 ::arg().setSwitch("secondary", "Act as a secondary") = "no";
ad5f04f1 228 ::arg().setSwitch("primary", "Act as a primary") = "no";
734646dd 229 ::arg().setSwitch("autosecondary", "Act as an autosecondary") = "no";
ad5f04f1
CH
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";
7bd9b307 235 ::arg().set("delay-notifications", "Configure a delay to send out notifications, no delay by default") = "0";
ad5f04f1
CH
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";
8ca656a8 245 ::arg().set("webserver-loglevel", "Amount of logging in the webserver (none, normal, detailed)") = "normal";
ad5f04f1
CH
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";
dea466f3 248
ad5f04f1 249 ::arg().setSwitch("query-logging", "Hint backends that queries should be logged") = "no";
952d3fcb 250
ad5f04f1
CH
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";
952d3fcb 256
ad5f04f1
CH
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";
30285d45 260 ::arg().set("zone-cache-refresh-interval", "Seconds to cache list of known zones") = "300";
ad5f04f1
CH
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";
58753225 266 ::arg().set("domain-metadata-cache-ttl", "Seconds to cache zone metadata from the database") = "";
b810842e 267 ::arg().set("zone-metadata-cache-ttl", "Seconds to cache zone metadata from the database") = "60";
dea466f3 268
ad5f04f1 269 ::arg().set("trusted-notification-proxy", "IP address of incoming notification proxy") = "";
ad5f04f1 270 ::arg().set("secondary-do-renotify", "If this secondary should send out notifications after receiving zone transfers from a primary") = "no";
c02c999b 271 ::arg().set("forward-notify", "IP addresses to forward received notifications to regardless of primary or secondary settings") = "";
ad5f04f1
CH
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";
5a5d565f 300 ::arg().set("max-nsec3-iterations", "Limit the number of NSEC3 hash iterations") = "100";
ad5f04f1
CH
301 ::arg().set("default-publish-cdnskey", "Default value for PUBLISH-CDNSKEY") = "";
302 ::arg().set("default-publish-cds", "Default value for PUBLISH-CDS") = "";
0a862860 303
ad5f04f1 304 ::arg().set("include-dir", "Include *.conf files from this directory");
2dc0dd0c 305 ::arg().set("security-poll-suffix", "Zone name from which to query security update notifications") = "secpoll.powerdns.com.";
7f6f4d4f 306
ad5f04f1 307 ::arg().setSwitch("expand-alias", "Expand ALIAS records") = "no";
833b07fe 308 ::arg().set("outgoing-axfr-expand-alias", "Expand ALIAS records during outgoing AXFR") = "no";
ad5f04f1 309 ::arg().setSwitch("8bit-dns", "Allow 8bit dns queries") = "no";
af68014f 310#ifdef HAVE_LUA_RECORDS
ad5f04f1
CH
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";
a6be268f
CHB
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";
af68014f 317#endif
d525b58b 318 ::arg().setSwitch("axfr-lower-serial", "Also AXFR a zone from a primary with a lower serial") = "no";
db8f9152 319
ad5f04f1
CH
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";
940d7811 323
ad5f04f1 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";
e97cb679 325
ad5f04f1
CH
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";
ba3d53d1 330
2dc0dd0c 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";
bd8df5bc 332
ad5f04f1 333 ::arg().set("rng", "Specify the random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.") = "auto";
c8734ecd
PD
334
335 ::arg().set("default-catalog-zone", "Catalog zone to assign newly created primary zones (via the API) to") = "";
7bd9b307 336
c113acc3 337#ifdef ENABLE_GSS_TSIG
fd7bbdb7 338 ::arg().setSwitch("enable-gss-tsig", "Enable GSS TSIG processing") = "no";
c113acc3 339#endif
8864bdf6 340 ::arg().setDefaults();
619e8acc
BH
341}
342
ad5f04f1 343static time_t s_start = time(nullptr);
d73de874 344static uint64_t uptimeOfProcess(const std::string& /* str */)
e903706d 345{
4646277d 346 return time(nullptr) - s_start;
e903706d 347}
348
349static uint64_t getSysUserTimeMsec(const std::string& str)
350{
351 struct rusage ru;
352 getrusage(RUSAGE_SELF, &ru);
353
ad5f04f1
CH
354 if (str == "sys-msec") {
355 return (ru.ru_stime.tv_sec * 1000ULL + ru.ru_stime.tv_usec / 1000);
a2746484 356 }
e903706d 357 else
ad5f04f1 358 return (ru.ru_utime.tv_sec * 1000ULL + ru.ru_utime.tv_usec / 1000);
e903706d 359}
360
d73de874 361static uint64_t getTCPConnectionCount(const std::string& /* str */)
d322f931 362{
6738003e 363 return s_tcpNameserver->numTCPConnections();
d322f931
PD
364}
365
d73de874 366static uint64_t getQCount(const std::string& /* str */)
ad5f04f1
CH
367try {
368 int totcount = 0;
346872ff 369 for (const auto& d : s_distributors) {
ad5f04f1 370 if (!d)
ba98c6d7 371 continue;
ad5f04f1 372 totcount += d->getQueueSize(); // this does locking and other things, so don't get smart
1a46890f 373 }
374 return totcount;
375}
ad5f04f1
CH
376catch (std::exception& e) {
377 g_log << Logger::Error << "Had error retrieving queue sizes: " << e.what() << endl;
2bf07cf4 378 return 0;
379}
ad5f04f1
CH
380catch (PDNSException& e) {
381 g_log << Logger::Error << "Had error retrieving queue sizes: " << e.reason << endl;
2bf07cf4 382 return 0;
383}
1a46890f 384
d73de874 385static uint64_t getLatency(const std::string& /* str */)
1a46890f 386{
6fd633be 387 return round(avg_latency);
1a46890f 388}
389
d73de874 390static uint64_t getReceiveLatency(const std::string& /* str */)
386c5b13
KM
391{
392 return round(receive_latency);
393}
394
d73de874 395static uint64_t getCacheLatency(const std::string& /* str */)
386c5b13
KM
396{
397 return round(cache_latency);
398}
399
d73de874 400static uint64_t getBackendLatency(const std::string& /* str */)
386c5b13
KM
401{
402 return round(backend_latency);
403}
404
d73de874 405static uint64_t getSendLatency(const std::string& /* str */)
386c5b13
KM
406{
407 return round(send_latency);
408}
409
8de02315 410static void declareStats()
619e8acc 411{
ad5f04f1
CH
412 S.declare("udp-queries", "Number of UDP queries received");
413 S.declare("udp-do-queries", "Number of UDP queries received with DO bit");
78f1d7b5 414 S.declare("udp-cookie-queries", "Number of UDP queries received with the COOKIE EDNS option");
ad5f04f1
CH
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");
bd852e59 419
ad5f04f1
CH
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");
bd852e59 425
bb6e54fe 426 S.declare("rd-queries", "Number of recursion desired questions");
427 S.declare("recursion-unanswered", "Number of packets unanswered by configured recursor");
ad5f04f1
CH
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");
c681ff64 431 S.declare("signatures", "Number of DNSSEC signatures made");
ad5f04f1
CH
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");
50dbdbeb 438
ad5f04f1
CH
439 S.declare("tcp4-queries", "Number of IPv4 TCP queries received");
440 S.declare("tcp4-answers", "Number of IPv4 answers sent out over TCP");
d322f931 441
ad5f04f1
CH
442 S.declare("tcp6-queries", "Number of IPv6 TCP queries received");
443 S.declare("tcp6-answers", "Number of IPv6 answers sent out over TCP");
619e8acc 444
ad5f04f1
CH
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);
619e8acc 448
71f758e0
KM
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.");
619e8acc 453
93aecccc
RK
454 S.declare("incoming-notifications", "NOTIFY packets received.");
455
dec69610
MTH
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);
f45a622c 460#ifdef __linux__
dec69610
MTH
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);
c0f5b6e8 465 S.declare("udp-in-csum-errors", "UDP 'in checksum' errors", udpErrorStats, StatType::counter);
db102a10
RG
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);
f45a622c 471#endif
472
dec69610
MTH
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);
149a72d8
RG
475
476#ifdef __linux__
dec69610
MTH
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);
149a72d8
RG
479#endif
480
dec69610
MTH
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);
e903706d 484
ad5f04f1
CH
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");
2dc0dd0c 488 S.declare("unauth-packets", "Number of times a zone we are not auth for was queried");
ad5f04f1 489 S.declare("latency", "Average number of microseconds needed to answer a question", getLatency, StatType::gauge);
386c5b13
KM
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);
ad5f04f1 494 S.declare("timedout-packets", "Number of packets which weren't answered within timeout set");
33b222ed 495 S.declare("security-status", "Security status based on regular polling", StatType::gauge);
2dc0dd0c
KM
496 S.declare(
497 "xfr-queue", "Size of the queue of zones to be XFRd", [](const string&) { return Communicator.getSuckRequestsWaiting(); }, StatType::gauge);
ad5f04f1 498 S.declareDNSNameQTypeRing("queries", "UDP Queries Received");
e746a2f6 499 S.declareDNSNameQTypeRing("nxdomain-queries", "Queries for nonexistent records within existent zones");
ad5f04f1
CH
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");
2dc0dd0c 502 S.declareDNSNameQTypeRing("unauth-queries", "Queries for zones that we are not authoritative for");
ad5f04f1
CH
503 S.declareRing("logmessages", "Log Messages");
504 S.declareComboRing("remotes", "Remote server IP addresses");
2dc0dd0c 505 S.declareComboRing("remotes-unauth", "Remote hosts querying zones for which we are not auth");
ad5f04f1 506 S.declareComboRing("remotes-corrupt", "Remote hosts sending corrupt packets");
619e8acc
BH
507}
508
8de02315 509static int isGuarded(char** argv)
619e8acc 510{
ad5f04f1 511 char* p = strstr(argv[0], "-instance");
619e8acc
BH
512
513 return !!p;
514}
515
386c5b13 516static void sendout(std::unique_ptr<DNSPacket>& a, int start)
619e8acc 517{
ad5f04f1 518 if (!a)
619e8acc 519 return;
bd852e59 520
b226e8fa 521 try {
386c5b13
KM
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
dd81fb3b 526 s_udpNameserver->send(*a);
b226e8fa 527
386c5b13
KM
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);
b226e8fa
RG
532 }
533 catch (const std::exception& e) {
ad5f04f1 534 g_log << Logger::Error << "Caught unhandled exception while sending a response: " << e.what() << endl;
b226e8fa 535 }
619e8acc
BH
536}
537
abc1d928 538//! The qthread receives questions over the internet via the Nameserver class, and hands them to the Distributor for further processing
c2826d2e 539static void qthread(unsigned int num)
ad5f04f1 540try {
519f5484 541 setThreadName("pdns/receiver");
09b12b5d 542
346872ff
CH
543 s_distributors[num] = DNSDistributor::Create(::arg().asNum("distributor-threads", 1));
544 DNSDistributor* distributor = s_distributors[num]; // the big dispatcher!
27c0050c
RG
545 DNSPacket question(true);
546 DNSPacket cached(false);
619e8acc 547
ad5f04f1
CH
548 AtomicCounter& numreceived = *S.getPointer("udp-queries");
549 AtomicCounter& numreceiveddo = *S.getPointer("udp-do-queries");
550 AtomicCounter& numreceivedcookie = *S.getPointer("udp-cookie-queries");
bd852e59 551
ad5f04f1 552 AtomicCounter& numreceived4 = *S.getPointer("udp4-queries");
bd852e59 553
ad5f04f1
CH
554 AtomicCounter& numreceived6 = *S.getPointer("udp6-queries");
555 AtomicCounter& overloadDrops = *S.getPointer("overload-drops");
90b07284 556
386c5b13 557 int diff, start;
21a303f3 558 bool logDNSQueries = ::arg().mustDo("log-dns-queries");
12f224ab 559 shared_ptr<UDPNameserver> NS;
2c001eb6 560 std::string buffer;
208abc4c 561 ComboAddress accountremote;
4ee30c66
MZ
562
563 // If we have SO_REUSEPORT then create a new port for all receiver threads
564 // other than the first one.
dd81fb3b 565 if (s_udpNameserver->canReusePort()) {
fcab180d 566 NS = s_udpReceivers[num];
12f224ab 567 if (NS == nullptr) {
dd81fb3b 568 NS = s_udpNameserver;
ed3afdfc 569 }
ad5f04f1
CH
570 }
571 else {
dd81fb3b 572 NS = s_udpNameserver;
3a56adcc 573 }
4ee30c66 574
ad5f04f1 575 for (;;) {
b226e8fa
RG
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 }
4172a5b2 583
ad5f04f1
CH
584 if (!NS->receive(question, buffer)) { // receive a packet inline
585 continue; // packet was broken, try again
b226e8fa
RG
586 }
587
386c5b13
KM
588 diff = question.d_dt.udiffNoReset();
589 receive_latency = 0.999 * receive_latency + 0.001 * std::max(diff, 0);
590
b226e8fa 591 numreceived++;
fe172793 592
208abc4c
KM
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)
b226e8fa
RG
598 numreceived4++;
599 else
600 numreceived6++;
8a63d3ce 601
ad5f04f1 602 if (question.d_dnssecOk)
b226e8fa 603 numreceiveddo++;
619e8acc 604
ad5f04f1 605 if (question.hasEDNSCookie())
b226e8fa 606 numreceivedcookie++;
9951e2d0 607
ad5f04f1 608 if (question.d.qr)
b226e8fa 609 continue;
78f1d7b5 610
b226e8fa 611 S.ringAccount("queries", question.qdomain, question.qtype);
531fce77 612 S.ringAccount("remotes", question.getInnerRemote());
ad5f04f1
CH
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 << ")";
b226e8fa 617 }
6a90bacf 618
ad5f04f1 619 if (PC.enabled() && (question.d.opcode != Opcode::Notify && question.d.opcode != Opcode::Update) && question.couldBeCached()) {
386c5b13 620 start = diff;
ad5f04f1 621 bool haveSomething = PC.get(question, cached); // does the PacketCache recognize this question?
b226e8fa 622 if (haveSomething) {
ad5f04f1
CH
623 if (logDNSQueries)
624 g_log << ": packetcache HIT" << endl;
625 cached.setRemote(&question.d_remote); // inlined
208abc4c 626 cached.d_inner_remote = question.d_inner_remote;
ad5f04f1 627 cached.setSocket(question.getSocket()); // inlined
b226e8fa
RG
628 cached.d_anyLocal = question.d_anyLocal;
629 cached.setMaxReplyLen(question.getMaxReplyLen());
ad5f04f1
CH
630 cached.d.rd = question.d.rd; // copy in recursion desired bit
631 cached.d.id = question.d.id;
b226e8fa 632 cached.commitD(); // commit d to the packet inlined
386c5b13
KM
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
b226e8fa 638 NS->send(cached); // answer it then inlined
386c5b13 639
ad5f04f1 640 diff = question.d_dt.udiff();
386c5b13
KM
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'
b226e8fa
RG
643 continue;
644 }
386c5b13
KM
645 diff = question.d_dt.udiffNoReset();
646 cache_latency = 0.999 * cache_latency + 0.001 * std::max(diff - start, 0);
b226e8fa 647 }
abc8f3f9 648
ad5f04f1
CH
649 if (distributor->isOverloaded()) {
650 if (logDNSQueries)
651 g_log << ": Dropped query, backends are overloaded" << endl;
b226e8fa 652 overloadDrops++;
75fde355
KM
653 continue;
654 }
bbe4b041 655
b226e8fa
RG
656 if (logDNSQueries) {
657 if (PC.enabled()) {
ad5f04f1
CH
658 g_log << ": packetcache MISS" << endl;
659 }
660 else {
661 g_log << endl;
b226e8fa 662 }
bbe4b041 663 }
e7e691cc 664
b226e8fa
RG
665 try {
666 distributor->question(question, &sendout); // otherwise, give to the distributor
667 }
ad5f04f1 668 catch (DistributorFatal& df) { // when this happens, we have leaked loads of memory. Bailing out time.
b226e8fa
RG
669 _exit(1);
670 }
491d03d7 671 }
b226e8fa 672 catch (const std::exception& e) {
ad5f04f1 673 g_log << Logger::Error << "Caught unhandled exception in question thread: " << e.what() << endl;
491d03d7 674 }
619e8acc 675 }
619e8acc 676}
ad5f04f1
CH
677catch (PDNSException& pe) {
678 g_log << Logger::Error << "Fatal error in question thread: " << pe.reason << endl;
26d75dc2 679 _exit(1);
680}
619e8acc 681
9092419e 682static void dummyThread()
2250bafa 683{
2250bafa 684}
685
686static void triggerLoadOfLibraries()
687{
9092419e
RG
688 std::thread dummy(dummyThread);
689 dummy.join();
2250bafa 690}
691
8de02315 692static void mainthread()
619e8acc 693{
ad5f04f1
CH
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");
8900e2e3 703#ifdef HAVE_LUA_RECORDS
ad5f04f1
CH
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");
a6be268f
CHB
708 g_luaConsistentHashesExpireDelay = ::arg().asNum("lua-consistent-hashes-expire-delay");
709 g_luaConsistentHashesCleanupInterval = ::arg().asNum("lua-consistent-hashes-cleanup-interval");
ad5f04f1 710 g_luaHealthChecksExpireDelay = ::arg().asNum("lua-health-checks-expire-delay");
8900e2e3 711#endif
c113acc3 712#ifdef ENABLE_GSS_TSIG
fd7bbdb7 713 g_doGssTSIG = ::arg().mustDo("enable-gss-tsig");
c113acc3 714#endif
8dee0750 715
ad5f04f1
CH
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");
199631c6 719
ad5f04f1
CH
720 g_proxyProtocolACL.toMasks(::arg()["proxy-protocol-from"]);
721 g_proxyProtocolMaximumSize = ::arg().asNum("proxy-protocol-maximum-size");
4172a5b2 722
ad5f04f1
CH
723 if (::arg()["edns-cookie-secret"].size() != 0) {
724 // User wants cookie processing
37063755 725#ifdef HAVE_CRYPTO_SHORTHASH // we can do siphash-based cookies
ad5f04f1
CH
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 }
37063755 737#else
ad5f04f1
CH
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);
37063755 740#endif
ad5f04f1 741 }
37063755 742
ad5f04f1
CH
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"));
bf269e28 747
ad5f04f1
CH
748 if (!PC.enabled() && ::arg().mustDo("log-dns-queries")) {
749 g_log << Logger::Warning << "Packet cache disabled, logging queries without HIT/MISS" << endl;
750 }
d786e4d4
CH
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 }
1b16851b 754
ad5f04f1 755 stubParseResolveConf();
199631c6 756
ad5f04f1 757 if (!::arg()["chroot"].empty()) {
75336810 758#ifdef HAVE_SYSTEMD
ad5f04f1
CH
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 }
75336810 765#endif
ad5f04f1
CH
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 }
357f6a75 780
dea47634 781 AuthWebServer webserver;
f1d6a7ce 782 Utility::dropUserPrivs(newuid);
619e8acc 783
ad5f04f1 784 if (::arg().mustDo("resolver")) {
2bbc9eb0 785 DP = std::make_unique<DNSProxy>(::arg()["resolver"]);
619e8acc
BH
786 DP->go();
787 }
e6402e23
PL
788
789 try {
790 doSecPoll(true);
791 }
ad5f04f1
CH
792 catch (...) {
793 }
e6402e23 794
efc10591
PL
795 {
796 // Some sanity checking on default key settings
797 bool hadKeyError = false;
798 int kskAlgo{0}, zskAlgo{0};
844535e5 799 for (const string algotype : {"ksk", "zsk"}) {
efc10591 800 int algo, size;
ad5f04f1 801 if (::arg()["default-" + algotype + "-algorithm"].empty())
efc10591 802 continue;
ad5f04f1
CH
803 algo = DNSSECKeeper::shorthand2algorithm(::arg()["default-" + algotype + "-algorithm"]);
804 size = ::arg().asNum("default-" + algotype + "-size");
efc10591 805 if (algo == -1) {
ad5f04f1 806 g_log << Logger::Error << "Error: default-" << algotype << "-algorithm set to unknown algorithm: " << ::arg()["default-" + algotype + "-algorithm"] << endl;
efc10591
PL
807 hadKeyError = true;
808 }
809 else if (algo <= 10 && size == 0) {
ad5f04f1 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;
efc10591
PL
811 hadKeyError = true;
812 }
813 if (algotype == "ksk") {
814 kskAlgo = algo;
ad5f04f1
CH
815 }
816 else {
efc10591
PL
817 zskAlgo = algo;
818 }
8b8e8670 819 }
efc10591
PL
820 if (hadKeyError) {
821 exit(1);
822 }
823 if (kskAlgo == 0 && zskAlgo != 0) {
ad5f04f1 824 g_log << Logger::Error << "Error: default-zsk-algorithm is set, but default-ksk-algorithm is not set." << endl;
efc10591
PL
825 exit(1);
826 }
827 if (zskAlgo != 0 && zskAlgo != kskAlgo) {
ad5f04f1 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;
efc10591 829 exit(1);
8b8e8670 830 }
82ee5aa5
PL
831 }
832
20829585 833 pdns::parseQueryLocalAddress(::arg()["query-local-address"]);
20829585 834
1886a4b3
PL
835 pdns::parseTrustedNotificationProxy(::arg()["trusted-notification-proxy"]);
836
cfb35c2f
KM
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
619e8acc 854 // NOW SAFE TO CREATE THREADS!
a270fbcb 855 s_dynListener->go();
619e8acc 856
a690b08c
FM
857 if (::arg().mustDo("webserver") || ::arg().mustDo("api")) {
858 webserver.go(S);
859 }
dea47634 860
ad5f04f1
CH
861 if (::arg().mustDo("primary") || ::arg().mustDo("secondary") || !::arg()["forward-notify"].empty())
862 Communicator.go();
619e8acc 863
6738003e 864 s_tcpNameserver->go(); // tcp nameserver launch
952d3fcb 865
ad5f04f1 866 unsigned int max_rthreads = ::arg().asNum("receiver-threads", 1);
346872ff 867 s_distributors.resize(max_rthreads);
ad5f04f1 868 for (unsigned int n = 0; n < max_rthreads; ++n) {
c2826d2e
RG
869 std::thread t(qthread, n);
870 t.detach();
871 }
619e8acc 872
ad5f04f1 873 std::thread carbonThread(carbonDumpThread); // runs even w/o carbon, might change @ runtime
ba98c6d7 874
6988eae9
PL
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 */
ad5f04f1 881 sd_notify(0, "READY=1");
6988eae9
PL
882#endif
883
d5385b35
CH
884 const uint32_t secpollInterval = 1800;
885 uint32_t secpollSince = 0;
1f0fb39a 886 uint32_t zoneCacheUpdateSince = 0;
ad5f04f1 887 for (;;) {
1f0fb39a 888 const uint32_t sleeptime = g_zoneCache.getRefreshInterval() == 0 ? secpollInterval : std::min(secpollInterval, g_zoneCache.getRefreshInterval());
ad5f04f1 889 sleep(sleeptime); // if any signals arrive, we might run more often than expected.
d5385b35 890
1f0fb39a
CH
891 zoneCacheUpdateSince += sleeptime;
892 if (zoneCacheUpdateSince >= g_zoneCache.getRefreshInterval()) {
a65da20c
CH
893 try {
894 UeberBackend B;
1f0fb39a
CH
895 B.updateZoneCache();
896 zoneCacheUpdateSince = 0;
a65da20c 897 }
ad5f04f1
CH
898 catch (PDNSException& e) {
899 g_log << Logger::Error << "PDNSException while updating zone cache: " << e.reason << endl;
a65da20c 900 }
ad5f04f1
CH
901 catch (std::exception& e) {
902 g_log << Logger::Error << "STL Exception while updating zone cache: " << e.what() << endl;
a65da20c 903 }
d5385b35
CH
904 }
905
6e97d53c 906 secpollSince += sleeptime;
d5385b35
CH
907 if (secpollSince >= secpollInterval) {
908 secpollSince = 0;
909 try {
910 doSecPoll(false);
911 }
ad5f04f1
CH
912 catch (...) {
913 }
ea272da2 914 }
199631c6 915 }
ad5f04f1
CH
916
917 g_log << Logger::Error << "Mainthread exiting - should never happen" << endl;
619e8acc 918}
8cb70f23
CH
919
920static void daemonize()
921{
ad5f04f1 922 if (fork())
8cb70f23
CH
923 exit(0); // bye bye
924
925 setsid();
926
ad5f04f1
CH
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;
8cb70f23 930 else {
ad5f04f1
CH
931 dup2(i, 0); /* stdin */
932 dup2(i, 1); /* stderr */
933 dup2(i, 2); /* stderr */
8cb70f23
CH
934 close(i);
935 }
936}
937
938static int cpid;
d73de874 939static void takedown(int /* i */)
8cb70f23 940{
ad5f04f1
CH
941 if (cpid) {
942 g_log << Logger::Error << "Guardian is killed, taking down children with us" << endl;
943 kill(cpid, SIGKILL);
8cb70f23
CH
944 exit(0);
945 }
946}
947
948static void writePid()
949{
ad5f04f1 950 if (!::arg().mustDo("write-pid"))
8cb70f23
CH
951 return;
952
ad5f04f1 953 string fname = ::arg()["socket-dir"];
8cb70f23
CH
954 if (::arg()["socket-dir"].empty()) {
955 if (::arg()["chroot"].empty())
956 fname = std::string(LOCALSTATEDIR) + "/pdns";
957 else
958 fname = ::arg()["chroot"] + "/";
ad5f04f1
CH
959 }
960 else if (!::arg()["socket-dir"].empty() && !::arg()["chroot"].empty()) {
8cb70f23
CH
961 fname = ::arg()["chroot"] + ::arg()["socket-dir"];
962 }
963
c509c9fa 964 fname += +"/" + g_programname + ".pid";
8cb70f23 965 ofstream of(fname.c_str());
ad5f04f1
CH
966 if (of)
967 of << getpid() << endl;
8cb70f23 968 else
ad5f04f1 969 g_log << Logger::Error << "Writing pid for " << getpid() << " to " << fname << " failed: " << stringerror() << endl;
8cb70f23
CH
970}
971
972static int g_fd1[2], g_fd2[2];
ad5f04f1 973static FILE* g_fp;
8cb70f23
CH
974static 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.
d73de874 977static string DLCycleHandler(const vector<string>& /* parts */, pid_t /* ppid */)
8cb70f23
CH
978{
979 kill(cpid, SIGKILL); // why?
980 kill(cpid, SIGKILL); // why?
981 sleep(1);
982 return "ok";
983}
984
d73de874 985static string DLRestHandler(const vector<string>& parts, pid_t /* ppid */)
8cb70f23
CH
986{
987 string line;
988
ad5f04f1
CH
989 for (vector<string>::const_iterator i = parts.begin(); i != parts.end(); ++i) {
990 if (i != parts.begin())
991 line.append(1, ' ');
8cb70f23
CH
992 line.append(*i);
993 }
ad5f04f1 994 line.append(1, '\n');
8cb70f23
CH
995
996 std::lock_guard<std::mutex> l(g_guardian_lock);
997
998 try {
ad5f04f1 999 writen2(g_fd1[1], line.c_str(), line.size() + 1);
8cb70f23 1000 }
ad5f04f1
CH
1001 catch (PDNSException& ae) {
1002 return "Error communicating with instance: " + ae.reason;
8cb70f23
CH
1003 }
1004 char mesg[512];
1005 string response;
ad5f04f1
CH
1006 while (fgets(mesg, sizeof(mesg), g_fp)) {
1007 if (*mesg == '\0')
8cb70f23 1008 break;
ad5f04f1 1009 response += mesg;
8cb70f23
CH
1010 }
1011 boost::trim_right(response);
1012 return response;
1013}
1014
ad5f04f1 1015static int guardian(int argc, char** argv)
8cb70f23 1016{
ad5f04f1 1017 if (isGuarded(argv))
8cb70f23
CH
1018 return 0;
1019
ad5f04f1 1020 int infd = 0, outfd = 1;
8cb70f23 1021
c509c9fa 1022 DynListener dlg(g_programname);
ad5f04f1
CH
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");
8cb70f23
CH
1027 dlg.registerRestFunc(&DLRestHandler);
1028 dlg.go();
ad5f04f1 1029 string progname = argv[0];
8cb70f23 1030
ad5f04f1
CH
1031 bool first = true;
1032 cpid = 0;
8cb70f23
CH
1033
1034 g_guardian_lock.lock();
1035
ad5f04f1 1036 for (;;) {
8cb70f23
CH
1037 int pid;
1038 setStatus("Launching child");
1039
ad5f04f1
CH
1040 if (pipe(g_fd1) < 0 || pipe(g_fd2) < 0) {
1041 g_log << Logger::Critical << "Unable to open pipe for coprocess: " << stringerror() << endl;
8cb70f23
CH
1042 exit(1);
1043 }
1044
ad5f04f1
CH
1045 if (!(g_fp = fdopen(g_fd2[0], "r"))) {
1046 g_log << Logger::Critical << "Unable to associate a file pointer with pipe: " << stringerror() << endl;
8cb70f23
CH
1047 exit(1);
1048 }
ad5f04f1 1049 setbuf(g_fp, nullptr); // no buffering please, confuses select
8cb70f23 1050
ad5f04f1 1051 if (!(pid = fork())) { // child
8cb70f23
CH
1052 signal(SIGTERM, SIG_DFL);
1053
1054 signal(SIGHUP, SIG_DFL);
1055 signal(SIGUSR1, SIG_DFL);
1056 signal(SIGUSR2, SIG_DFL);
1057
ad5f04f1 1058 char** const newargv = new char*[argc + 2];
8cb70f23
CH
1059 int n;
1060
ad5f04f1
CH
1061 if (::arg()["config-name"] != "") {
1062 progname += "-" + ::arg()["config-name"];
1063 g_log << Logger::Error << "Virtual configuration name: " << ::arg()["config-name"] << endl;
8cb70f23
CH
1064 }
1065
ad5f04f1
CH
1066 newargv[0] = strdup(const_cast<char*>((progname + "-instance").c_str()));
1067 for (n = 1; n < argc; n++) {
1068 newargv[n] = argv[n];
8cb70f23 1069 }
ad5f04f1 1070 newargv[n] = nullptr;
8cb70f23 1071
ad5f04f1 1072 g_log << Logger::Error << "Guardian is launching an instance" << endl;
8cb70f23
CH
1073 close(g_fd1[1]);
1074 fclose(g_fp); // this closes g_fd2[0] for us
1075
ad5f04f1 1076 if (g_fd1[0] != infd) {
8cb70f23
CH
1077 dup2(g_fd1[0], infd);
1078 close(g_fd1[0]);
1079 }
1080
ad5f04f1 1081 if (g_fd2[1] != outfd) {
8cb70f23
CH
1082 dup2(g_fd2[1], outfd);
1083 close(g_fd2[1]);
1084 }
ad5f04f1
CH
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;
8cb70f23
CH
1090
1091 exit(1);
1092 }
ad5f04f1 1093 g_log << Logger::Error << "execvp returned!!" << endl;
8cb70f23
CH
1094 // never reached
1095 }
ad5f04f1 1096 else if (pid > 0) { // parent
8cb70f23
CH
1097 close(g_fd1[0]);
1098 close(g_fd2[1]);
1099
ad5f04f1
CH
1100 if (first) {
1101 first = false;
8cb70f23
CH
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;
ad5f04f1
CH
1112 cpid = pid;
1113 for (;;) {
1114 int ret = waitpid(pid, &status, WNOHANG);
8cb70f23 1115
ad5f04f1
CH
1116 if (ret < 0) {
1117 g_log << Logger::Error << "In guardian loop, waitpid returned error: " << stringerror() << endl;
1118 g_log << Logger::Error << "Dying" << endl;
8cb70f23
CH
1119 exit(1);
1120 }
ad5f04f1 1121 else if (ret) // something exited
8cb70f23
CH
1122 break;
1123 else { // child is alive
1124 // execute some kind of ping here
ad5f04f1 1125 if (DLQuitPlease())
8cb70f23 1126 takedown(1); // needs a parameter..
564db8c5 1127 setStatus("Child running on pid " + std::to_string(pid));
8cb70f23
CH
1128 sleep(1);
1129 }
1130 }
1131
1132 g_guardian_lock.lock();
1133 close(g_fd1[1]);
1134 fclose(g_fp);
ad5f04f1 1135 g_fp = nullptr;
8cb70f23 1136
ad5f04f1
CH
1137 if (WIFEXITED(status)) {
1138 int ret = WEXITSTATUS(status);
8cb70f23 1139
ad5f04f1
CH
1140 if (ret == 99) {
1141 g_log << Logger::Error << "Child requested a stop, exiting" << endl;
8cb70f23
CH
1142 exit(1);
1143 }
564db8c5 1144 setStatus("Child died with code " + std::to_string(ret));
ad5f04f1 1145 g_log << Logger::Error << "Our pdns instance exited with code " << ret << ", respawning" << endl;
8cb70f23
CH
1146
1147 sleep(1);
1148 continue;
1149 }
ad5f04f1
CH
1150 if (WIFSIGNALED(status)) {
1151 int sig = WTERMSIG(status);
564db8c5 1152 setStatus("Child died because of signal " + std::to_string(sig));
ad5f04f1 1153 g_log << Logger::Error << "Our pdns instance (" << pid << ") exited after signal " << sig << endl;
8cb70f23 1154#ifdef WCOREDUMP
ad5f04f1
CH
1155 if (WCOREDUMP(status))
1156 g_log << Logger::Error << "Dumped core" << endl;
8cb70f23
CH
1157#endif
1158
ad5f04f1 1159 g_log << Logger::Error << "Respawning" << endl;
8cb70f23
CH
1160 sleep(1);
1161 continue;
1162 }
ad5f04f1 1163 g_log << Logger::Error << "No clue what happened! Respawning" << endl;
8cb70f23
CH
1164 }
1165 else {
ad5f04f1 1166 g_log << Logger::Error << "Unable to fork: " << stringerror() << endl;
8cb70f23
CH
1167 exit(1);
1168 }
1169 }
1170}
1171
1172#if defined(__GLIBC__) && !defined(__UCLIBC__)
1173#include <execinfo.h>
1174static void tbhandler(int num)
1175{
ad5f04f1
CH
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)
8cb70f23 1178 size_t size;
ad5f04f1 1179 char** strings;
8cb70f23
CH
1180 size_t i;
1181
ad5f04f1
CH
1182 size = backtrace(array, 20);
1183 strings = backtrace_symbols(array, size); // Need -rdynamic gcc (linker) flag for this to work
8cb70f23
CH
1184
1185 for (i = 0; i < size; i++) // skip useless functions
ad5f04f1 1186 g_log << Logger::Error << strings[i] << endl;
8cb70f23
CH
1187
1188 signal(SIGABRT, SIG_DFL);
1189 abort(); // hopefully will give core
1190}
1191#endif
1192
460a6daa
RG
1193#ifdef COVERAGE
1194static void sigTermHandler([[maybe_unused]] int signal)
1195{
1196 pdns::coverage::dumpCoverageData();
1197 _exit(EXIT_SUCCESS);
1198}
1199#endif /* COVERAGE */
1200
8cb70f23 1201//! The main function of pdns, the pdns process
ad5f04f1 1202int main(int argc, char** argv)
8cb70f23
CH
1203{
1204 versionSetProduct(ProductAuthoritative);
1205 reportAllTypes(); // init MOADNSParser
1206
c509c9fa
CH
1207 g_programname = "pdns";
1208 g_starttime = time(nullptr);
8cb70f23
CH
1209
1210#if defined(__GLIBC__) && !defined(__UCLIBC__)
ad5f04f1
CH
1211 signal(SIGSEGV, tbhandler);
1212 signal(SIGFPE, tbhandler);
1213 signal(SIGABRT, tbhandler);
1214 signal(SIGILL, tbhandler);
8cb70f23
CH
1215#endif
1216
1217 std::ios_base::sync_with_stdio(false);
1218
1219 g_log.toConsole(Logger::Warning);
1220 try {
1221 declareArguments();
1222
ad5f04f1 1223 ::arg().laxParse(argc, argv); // do a lax parse
8cb70f23 1224
ad5f04f1 1225 if (::arg().mustDo("version")) {
8cb70f23
CH
1226 showProductVersion();
1227 showBuildConfiguration();
fd5d471f 1228 return 0;
8cb70f23
CH
1229 }
1230
ad5f04f1 1231 if (::arg()["config-name"] != "")
c509c9fa 1232 g_programname += "-" + ::arg()["config-name"];
8cb70f23 1233
c509c9fa 1234 g_log.setName(g_programname);
8cb70f23 1235
c509c9fa 1236 string configname = ::arg()["config-dir"] + "/" + g_programname + ".conf";
8cb70f23
CH
1237 cleanSlashes(configname);
1238
ad5f04f1 1239 if (::arg()["config"] != "default" && !::arg().mustDo("no-config")) // "config" == print a configuration file
8cb70f23
CH
1240 ::arg().laxFile(configname.c_str());
1241
ad5f04f1
CH
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)
8cb70f23
CH
1246 g_log.setFacility(val);
1247 else
ad5f04f1 1248 g_log << Logger::Error << "Unknown logging facility " << ::arg().asNum("logging-facility") << endl;
8cb70f23
CH
1249 }
1250
8cb70f23
CH
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
8cb70f23
CH
1255 ::arg().set("domain-metadata-cache-ttl") = ::arg()["zone-metadata-cache-ttl"];
1256
1257 g_log.setLoglevel((Logger::Urgency)(::arg().asNum("loglevel")));
46eec001 1258 g_log.setPrefixed(::arg().mustDo("loglevel-show"));
8cb70f23
CH
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
ad5f04f1
CH
1263 if (::arg().mustDo("help") || ::arg().mustDo("config")) {
1264 ::arg().set("daemon") = "no";
1265 ::arg().set("guardian") = "no";
8cb70f23
CH
1266 }
1267
ad5f04f1
CH
1268 if (::arg().mustDo("guardian") && !isGuarded(argv)) {
1269 if (::arg().mustDo("daemon")) {
8cb70f23
CH
1270 g_log.toConsole(Logger::Critical);
1271 daemonize();
1272 }
1273 guardian(argc, argv);
1274 // never get here, guardian will reinvoke process
ad5f04f1 1275 cerr << "Um, we did get here!" << endl;
8cb70f23
CH
1276 }
1277
460a6daa
RG
1278#ifdef COVERAGE
1279 if (!::arg().mustDo("guardian") && !::arg().mustDo("daemon")) {
1280 signal(SIGTERM, sigTermHandler);
1281 }
1282#endif
1283
8cb70f23
CH
1284 // we really need to do work - either standalone or as an instance
1285
1286#if defined(__GLIBC__) && !defined(__UCLIBC__)
ad5f04f1
CH
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);
8cb70f23
CH
1293 }
1294#endif
1295
1296#ifdef HAVE_LIBSODIUM
ad5f04f1
CH
1297 if (sodium_init() == -1) {
1298 cerr << "Unable to initialize sodium crypto library" << endl;
1299 exit(99);
1300 }
8cb70f23
CH
1301#endif
1302
1303 openssl_thread_setup();
1304 openssl_seed();
8cb70f23
CH
1305
1306#ifdef HAVE_LUA_RECORDS
1307 MiniCurl::init();
1308#endif /* HAVE_LUA_RECORDS */
1309
ad5f04f1 1310 if (!::arg()["load-modules"].empty()) {
8cb70f23
CH
1311 vector<string> modules;
1312
ad5f04f1 1313 stringtok(modules, ::arg()["load-modules"], ", ");
8cb70f23
CH
1314 if (!UeberBackend::loadModules(modules, ::arg()["module-dir"])) {
1315 exit(1);
1316 }
1317 }
1318
1319 BackendMakers().launch(::arg()["launch"]); // vrooooom!
1320
ad5f04f1
CH
1321 if (!::arg().getCommands().empty()) {
1322 cerr << "Fatal: non-option";
8cb70f23 1323 if (::arg().getCommands().size() > 1) {
ad5f04f1 1324 cerr << "s";
8cb70f23 1325 }
ad5f04f1 1326 cerr << " (";
8cb70f23
CH
1327 bool first = true;
1328 for (const auto& c : ::arg().getCommands()) {
1329 if (!first) {
ad5f04f1 1330 cerr << ", ";
8cb70f23
CH
1331 }
1332 first = false;
ad5f04f1 1333 cerr << c;
8cb70f23 1334 }
ad5f04f1 1335 cerr << ") on the command line, perhaps a '--setting=123' statement missed the '='?" << endl;
8cb70f23
CH
1336 exit(99);
1337 }
1338
ad5f04f1
CH
1339 if (::arg().mustDo("help")) {
1340 cout << "syntax:" << endl
1341 << endl;
1342 cout << ::arg().helpstring(::arg()["help"]) << endl;
8cb70f23
CH
1343 exit(0);
1344 }
1345
ad5f04f1 1346 if (::arg().mustDo("config")) {
8cb70f23
CH
1347 string config = ::arg()["config"];
1348 if (config == "default") {
ad5f04f1
CH
1349 cout << ::arg().configstring(false, true);
1350 }
1351 else if (config == "diff") {
1352 cout << ::arg().configstring(true, false);
1353 }
1354 else if (config == "check") {
8cb70f23 1355 try {
ad5f04f1 1356 if (!::arg().mustDo("no-config"))
8cb70f23 1357 ::arg().file(configname.c_str());
ad5f04f1 1358 ::arg().parse(argc, argv);
8cb70f23
CH
1359 exit(0);
1360 }
ad5f04f1
CH
1361 catch (const ArgException& A) {
1362 cerr << "Fatal error: " << A.reason << endl;
8cb70f23
CH
1363 exit(1);
1364 }
ad5f04f1
CH
1365 }
1366 else {
1367 cout << ::arg().configstring(true, true);
8cb70f23
CH
1368 }
1369 exit(0);
1370 }
1371
ad5f04f1 1372 if (::arg().mustDo("list-modules")) {
8cb70f23 1373 auto modules = BackendMakers().getModules();
ad5f04f1
CH
1374 cout << "Modules available:" << endl;
1375 for (const auto& m : modules)
1376 cout << m << endl;
8cb70f23
CH
1377
1378 _exit(99);
1379 }
1380
ad5f04f1
CH
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;
8cb70f23
CH
1383 exit(99); // this isn't going to fix itself either
1384 }
ad5f04f1
CH
1385 if (!BackendMakers().numLauncheable()) {
1386 g_log << Logger::Error << "Unable to launch, no backends configured for querying" << endl;
8cb70f23
CH
1387 exit(99); // this isn't going to fix itself either
1388 }
ad5f04f1 1389 if (::arg().mustDo("daemon")) {
8cb70f23 1390 g_log.toConsole(Logger::None);
ad5f04f1 1391 if (!isGuarded(argv))
8cb70f23
CH
1392 daemonize();
1393 }
1394
ad5f04f1
CH
1395 if (isGuarded(argv)) {
1396 g_log << Logger::Warning << "This is a guarded instance of pdns" << endl;
a270fbcb 1397 s_dynListener = std::make_unique<DynListener>(); // listens on stdin
8cb70f23
CH
1398 }
1399 else {
ad5f04f1 1400 g_log << Logger::Warning << "This is a standalone pdns" << endl;
8cb70f23 1401
ad5f04f1 1402 if (::arg().mustDo("control-console"))
a270fbcb 1403 s_dynListener = std::make_unique<DynListener>();
8cb70f23 1404 else
a270fbcb 1405 s_dynListener = std::make_unique<DynListener>(g_programname);
8cb70f23
CH
1406
1407 writePid();
1408 }
ad5f04f1
CH
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");
8cb70f23
CH
1413 DynListener::registerFunc("NOTIFY-HOST", &DLNotifyHostHandler, "notify host for specific zone", "<zone> <host>");
1414 DynListener::registerFunc("NOTIFY", &DLNotifyHandler, "queue a notification", "<zone>");
ad5f04f1
CH
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");
8cb70f23
CH
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");
ad5f04f1 1423 DynListener::registerFunc("SET", &DLSettingsHandler, "set config variables", "<var> <value>");
c02c999b 1424 DynListener::registerFunc("RETRIEVE", &DLNotifyRetrieveHandler, "retrieve secondary zone", "<zone> [<ip>]");
ad5f04f1 1425 DynListener::registerFunc("CURRENT-CONFIG", &DLCurrentConfigHandler, "retrieve the current configuration", "[diff]");
d5540ff1 1426 DynListener::registerFunc("LIST-ZONES", &DLListZones, "show list of zones", "[primary|secondary|native|consumer|producer]");
8cb70f23
CH
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
ad5f04f1
CH
1430 if (!::arg()["tcp-control-address"].empty()) {
1431 DynListener* dlTCP = new DynListener(ComboAddress(::arg()["tcp-control-address"], ::arg().asNum("tcp-control-port")));
8cb70f23
CH
1432 dlTCP->go();
1433 }
1434
1435 // reparse, with error checking
ad5f04f1 1436 if (!::arg().mustDo("no-config"))
8cb70f23 1437 ::arg().file(configname.c_str());
ad5f04f1 1438 ::arg().parse(argc, argv);
8cb70f23 1439
ad5f04f1 1440 if (::arg()["server-id"].empty()) {
8cb70f23 1441 char tmp[128];
ad5f04f1
CH
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;
8cb70f23
CH
1447 }
1448 }
1449
dd81fb3b 1450 s_udpNameserver = std::make_shared<UDPNameserver>(); // this fails when we are not root, throws exception
fcab180d 1451 s_udpReceivers.push_back(s_udpNameserver);
8cb70f23
CH
1452
1453 size_t rthreads = ::arg().asNum("receiver-threads", 1);
dd81fb3b 1454 if (rthreads > 1 && s_udpNameserver->canReusePort()) {
fcab180d 1455 s_udpReceivers.resize(rthreads);
8cb70f23
CH
1456
1457 for (size_t idx = 1; idx < rthreads; idx++) {
1458 try {
fcab180d 1459 s_udpReceivers[idx] = std::make_shared<UDPNameserver>(true);
8cb70f23 1460 }
ad5f04f1
CH
1461 catch (const PDNSException& e) {
1462 g_log << Logger::Error << "Unable to reuse port, falling back to original bind" << endl;
8cb70f23
CH
1463 break;
1464 }
1465 }
1466 }
1467
6738003e 1468 s_tcpNameserver = make_unique<TCPNameserver>();
8cb70f23 1469 }
ad5f04f1
CH
1470 catch (const ArgException& A) {
1471 g_log << Logger::Error << "Fatal error: " << A.reason << endl;
8cb70f23
CH
1472 exit(1);
1473 }
0d757bd2
RG
1474 catch (const std::exception& e) {
1475 g_log << Logger::Error << "Fatal error: " << e.what() << endl;
1476 exit(1);
1477 }
8cb70f23
CH
1478
1479 try {
1480 declareStats();
1481 }
0d757bd2 1482 catch (const PDNSException& PE) {
ad5f04f1 1483 g_log << Logger::Error << "Exiting because: " << PE.reason << endl;
8cb70f23
CH
1484 exit(1);
1485 }
c8734ecd
PD
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 }
8cb70f23
CH
1497 S.blacklist("special-memory-usage");
1498
ad5f04f1 1499 DLOG(g_log << Logger::Warning << "Verbose logging in effect" << endl);
8cb70f23
CH
1500
1501 showProductVersion();
1502
1503 try {
1504 mainthread();
1505 }
0d757bd2
RG
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 }
ad5f04f1 1514 g_log << Logger::Error << "Exiting because: " << e.reason << endl;
8cb70f23 1515 }
0d757bd2
RG
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 }
ad5f04f1 1524 g_log << Logger::Error << "Exiting because of STL error: " << e.what() << endl;
8cb70f23 1525 }
ad5f04f1
CH
1526 catch (...) {
1527 cerr << "Uncaught exception of unknown type - sorry" << endl;
8cb70f23
CH
1528 }
1529
1530 exit(1);
1531}