• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 11049952298

26 Sep 2024 09:59AM UTC coverage: 64.7% (+0.005%) from 64.695%
11049952298

Pull #14594

github

web-flow
Merge b1726e0c0 into 42c3a1e1b
Pull Request #14594: auth udp: use stubDoResolve for ALIAS

37040 of 87934 branches covered (42.12%)

Branch coverage included in aggregate %.

25 of 54 new or added lines in 2 files covered. (46.3%)

53 existing lines in 14 files now uncovered.

124664 of 161993 relevant lines covered (76.96%)

4875762.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.47
/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 "utility.hh"
83
#include "dnsrecords.hh"
84
#include "version.hh"
85
#include "ws-auth.hh"
86

87
#ifdef HAVE_LUA_RECORDS
88
#include "minicurl.hh"
89
#endif /* HAVE_LUA_RECORDS */
90

91
time_t g_starttime;
92

93
string g_programname = "pdns"; // used in packethandler.cc
94

95
const char* funnytext = "*****************************************************************************\n"
96
                        "Ok, you just ran pdns-auth through 'strings' hoping to find funny messages.  \n"
97
                        "Well, you found one.                                                         \n"
98
                        "Two ions are flying through their particle accelerator, says the one to the  \n"
99
                        "other 'I think I've lost an electron!'                                       \n"
100
                        "So the other one says, 'Are you sure?'. 'YEAH! I'M POSITIVE!'                \n"
101
                        "                                                                             \n"
102
                        "                                            the pdns crew - pdns@powerdns.com\n"
103
                        "*****************************************************************************\n";
104

105
bool g_anyToTcp;
106
bool g_8bitDNS;
107
#ifdef HAVE_LUA_RECORDS
108
bool g_doLuaRecord;
109
int g_luaRecordExecLimit;
110
time_t g_luaHealthChecksInterval{5};
111
time_t g_luaHealthChecksExpireDelay{3600};
112
time_t g_luaConsistentHashesExpireDelay{86400};
113
time_t g_luaConsistentHashesCleanupInterval{3600};
114
#endif
115
#ifdef ENABLE_GSS_TSIG
116
bool g_doGssTSIG;
117
#endif
118
typedef Distributor<DNSPacket, DNSPacket, PacketHandler> DNSDistributor;
119

120
ArgvMap theArg;
121
StatBag S; //!< Statistics are gathered across PDNS via the StatBag class S
122
AuthPacketCache PC; //!< This is the main PacketCache, shared across all threads
123
AuthQueryCache QC;
124
AuthZoneCache g_zoneCache;
125
static std::unique_ptr<DynListener> s_dynListener{nullptr};
126
CommunicatorClass Communicator;
127
static double avg_latency{0.0}, receive_latency{0.0}, cache_latency{0.0}, backend_latency{0.0}, send_latency{0.0};
128
static unique_ptr<TCPNameserver> s_tcpNameserver{nullptr};
129
static vector<DNSDistributor*> s_distributors;
130
static shared_ptr<UDPNameserver> s_udpNameserver{nullptr};
131
static vector<std::shared_ptr<UDPNameserver>> s_udpReceivers;
132
NetmaskGroup g_proxyProtocolACL;
133
size_t g_proxyProtocolMaximumSize;
134

135
ArgvMap& arg()
136
{
1,479,633✔
137
  return theArg;
1,479,633✔
138
}
1,479,633✔
139

140
static void declareArguments()
141
{
256✔
142
  ::arg().set("config-dir", "Location of configuration directory (pdns.conf)") = SYSCONFDIR;
256✔
143
  ::arg().set("config-name", "Name of this virtual configuration - will rename the binary image") = "";
256✔
144
  ::arg().set("socket-dir", string("Where the controlsocket will live, ") + LOCALSTATEDIR + "/pdns when unset and not chrooted"
256✔
145
#ifdef HAVE_SYSTEMD
256✔
146
                + ". Set to the RUNTIME_DIRECTORY environment variable when that variable has a value (e.g. under systemd).")
256✔
147
    = "";
256✔
148
  auto runtimeDir = getenv("RUNTIME_DIRECTORY");
256✔
149
  if (runtimeDir != nullptr) {
256!
150
    ::arg().set("socket-dir") = runtimeDir;
×
151
  }
×
152
#else
153
              )
154
    = "";
155
#endif
156
  ::arg().set("module-dir", "Default directory for modules") = PKGLIBDIR;
256✔
157
  ::arg().set("chroot", "If set, chroot to this directory for more security") = "";
256✔
158
  ::arg().set("logging-facility", "Log under a specific facility") = "";
256✔
159
  ::arg().set("daemon", "Operate as a daemon") = "no";
256✔
160

161
  ::arg().set("local-port", "The port on which we listen") = "53";
256✔
162
  ::arg().setSwitch("dnsupdate", "Enable/Disable DNS update (RFC2136) support. Default is no.") = "no";
256✔
163
  ::arg().setSwitch("write-pid", "Write a PID file") = "yes";
256✔
164
  ::arg().set("allow-dnsupdate-from", "A global setting to allow DNS updates from these IP ranges.") = "127.0.0.0/8,::1";
256✔
165
  ::arg().setSwitch("dnsupdate-require-tsig", "Require TSIG secured DNS updates. Default is no.") = "no";
256✔
166
  ::arg().set("proxy-protocol-from", "A Proxy Protocol header is only allowed from these subnets, and is mandatory then too.") = "";
256✔
167
  ::arg().set("proxy-protocol-maximum-size", "The maximum size of a proxy protocol payload, including the TLV values") = "512";
256✔
168
  ::arg().setSwitch("send-signed-notify", "Send TSIG secured NOTIFY if TSIG key is configured for a zone") = "yes";
256✔
169
  ::arg().set("allow-unsigned-notify", "Allow unsigned notifications for TSIG secured zones") = "yes"; // FIXME: change to 'no' later
256✔
170
  ::arg().set("allow-unsigned-autoprimary", "Allow autoprimaries to create zones without TSIG signed NOTIFY") = "yes";
256✔
171
  ::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";
256✔
172
  ::arg().setSwitch("log-dns-details", "If PDNS should log DNS non-erroneous details") = "no";
256✔
173
  ::arg().setSwitch("log-dns-queries", "If PDNS should log all incoming DNS queries") = "no";
256✔
174
  ::arg().set("local-address", "Local IP addresses to which we bind") = "0.0.0.0, ::";
256✔
175
  ::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";
256✔
176
  ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options") = "no";
256✔
177
  ::arg().setSwitch("reuseport", "Enable higher performance on compliant kernels by using SO_REUSEPORT allowing each receiver thread to open its own socket") = "no";
256✔
178
  ::arg().set("query-local-address", "Source IP addresses for sending queries") = "0.0.0.0 ::";
256✔
179
  ::arg().set("overload-queue-length", "Maximum queuelength moving to packetcache only") = "0";
256✔
180
  ::arg().set("max-queue-length", "Maximum queuelength before considering situation lost") = "5000";
256✔
181

182
  ::arg().set("retrieval-threads", "Number of AXFR-retrieval threads for secondary operation") = "2";
256✔
183
  ::arg().setSwitch("api", "Enable/disable the REST API (including HTTP listener)") = "no";
256✔
184
  ::arg().set("api-key", "Static pre-shared authentication key for access to the REST API") = "";
256✔
185
  ::arg().setSwitch("default-api-rectify", "Default API-RECTIFY value for zones") = "yes";
256✔
186
  ::arg().setSwitch("dname-processing", "If we should support DNAME records") = "no";
256✔
187

188
  ::arg().setCmd("help", "Provide a helpful message");
256✔
189
  ::arg().setCmd("version", "Output version and compilation date");
256✔
190
  ::arg().setCmd("config", "Provide configuration file on standard output");
256✔
191
  ::arg().setCmd("list-modules", "Lists all modules available");
256✔
192
  ::arg().setCmd("no-config", "Don't parse configuration file");
256✔
193

194
  ::arg().set("version-string", "PowerDNS version in packets - full, anonymous, powerdns or custom") = "full";
256✔
195
  ::arg().set("control-console", "Debugging switch - don't use") = "no"; // but I know you will!
256✔
196
  ::arg().set("loglevel", "Amount of logging. Higher is more. Do not set below 3") = "4";
256✔
197
  ::arg().setSwitch("loglevel-show", "Include log level indicator in log output") = "no";
256✔
198
  ::arg().set("disable-syslog", "Disable logging to syslog, useful when running inside a supervisor that logs stderr") = "no";
256✔
199
  ::arg().set("log-timestamp", "Print timestamps in log lines") = "yes";
256✔
200
  ::arg().set("distributor-threads", "Default number of Distributor (backend) threads to start") = "3";
256✔
201
  ::arg().set("signing-threads", "Default number of signer threads to start") = "3";
256✔
202
  ::arg().setSwitch("workaround-11804", "Workaround for issue 11804: send single RR per AXFR chunk") = "no";
256✔
203
  ::arg().set("receiver-threads", "Default number of receiver threads to start") = "1";
256✔
204
  ::arg().set("queue-limit", "Maximum number of milliseconds to queue a query") = "1500";
256✔
205
  ::arg().set("resolver", "Use this resolver for ALIAS and the internal stub resolver") = "no";
256✔
206
  ::arg().set("dnsproxy-udp-port-range", "Select DNS Proxy outgoing UDP port from given range (lower upper)") = "10000 60000";
256✔
207
  ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate") = "1232";
256✔
208

209
  ::arg().set("config-name", "Name of this virtual configuration - will rename the binary image") = "";
256✔
210

211
  ::arg().set("load-modules", "Load this module - supply absolute or relative path") = "";
256✔
212
  ::arg().set("launch", "Which backends to launch and order to query them in") = "";
256✔
213
  ::arg().setSwitch("disable-axfr", "Disable zonetransfers but do allow TCP queries") = "no";
256✔
214
  ::arg().set("allow-axfr-ips", "Allow zonetransfers only to these subnets") = "127.0.0.0/8,::1";
256✔
215
  ::arg().set("only-notify", "Only send AXFR NOTIFY to these IP addresses or netmasks") = "0.0.0.0/0,::/0";
256✔
216
  ::arg().set("also-notify", "When notifying a zone, also notify these nameservers") = "";
256✔
217
  ::arg().set("allow-notify-from", "Allow AXFR NOTIFY from these IP ranges. If empty, drop all incoming notifies.") = "0.0.0.0/0,::/0";
256✔
218
  ::arg().set("xfr-cycle-interval", "Schedule primary/secondary SOA freshness checks once every .. seconds") = "60";
256✔
219
  ::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";
256✔
220

221
  ::arg().set("tcp-control-address", "If set, PowerDNS can be controlled over TCP on this address") = "";
256✔
222
  ::arg().set("tcp-control-port", "If set, PowerDNS can be controlled over TCP on this address") = "53000";
256✔
223
  ::arg().set("tcp-control-secret", "If set, PowerDNS can be controlled over TCP after passing this secret") = "";
256✔
224
  ::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";
256✔
225

226
  ::arg().setSwitch("secondary", "Act as a secondary") = "no";
256✔
227
  ::arg().setSwitch("primary", "Act as a primary") = "no";
256✔
228
  ::arg().setSwitch("autosecondary", "Act as an autosecondary") = "no";
256✔
229
  ::arg().setSwitch("disable-axfr-rectify", "Disable the rectify step during an outgoing AXFR. Only required for regression testing.") = "no";
256✔
230
  ::arg().setSwitch("guardian", "Run within a guardian process") = "no";
256✔
231
  ::arg().setSwitch("prevent-self-notification", "Don't send notifications to what we think is ourself") = "yes";
256✔
232
  ::arg().setSwitch("any-to-tcp", "Answer ANY queries with tc=1, shunting to TCP") = "yes";
256✔
233
  ::arg().setSwitch("edns-subnet-processing", "If we should act on EDNS Subnet options") = "no";
256✔
234
  ::arg().set("delay-notifications", "Configure a delay to send out notifications, no delay by default") = "0";
256✔
235

236
  ::arg().set("edns-cookie-secret", "When set, set a server cookie when responding to a query with a Client cookie (in hex)") = "";
256✔
237

238
  ::arg().setSwitch("webserver", "Start a webserver for monitoring (api=yes also enables the HTTP listener)") = "no";
256✔
239
  ::arg().setSwitch("webserver-print-arguments", "If the webserver should print arguments") = "no";
256✔
240
  ::arg().set("webserver-address", "IP Address of webserver/API to listen on") = "127.0.0.1";
256✔
241
  ::arg().set("webserver-port", "Port of webserver/API to listen on") = "8081";
256✔
242
  ::arg().set("webserver-password", "Password required for accessing the webserver") = "";
256✔
243
  ::arg().set("webserver-allow-from", "Webserver/API access is only allowed from these subnets") = "127.0.0.1,::1";
256✔
244
  ::arg().set("webserver-loglevel", "Amount of logging in the webserver (none, normal, detailed)") = "normal";
256✔
245
  ::arg().set("webserver-max-bodysize", "Webserver/API maximum request/response body size in megabytes") = "2";
256✔
246
  ::arg().set("webserver-connection-timeout", "Webserver/API request/response timeout in seconds") = "5";
256✔
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";
256✔
248

249
  ::arg().setSwitch("query-logging", "Hint backends that queries should be logged") = "no";
256✔
250

251
  ::arg().set("carbon-namespace", "If set overwrites the first part of the carbon string") = "pdns";
256✔
252
  ::arg().set("carbon-ourname", "If set, overrides our reported hostname for carbon stats") = "";
256✔
253
  ::arg().set("carbon-instance", "If set overwrites the instance name default") = "auth";
256✔
254
  ::arg().set("carbon-server", "If set, send metrics in carbon (graphite) format to this server IP address") = "";
256✔
255
  ::arg().set("carbon-interval", "Number of seconds between carbon (graphite) updates") = "30";
256✔
256

257
  ::arg().set("cache-ttl", "Seconds to store packets in the PacketCache") = "20";
256✔
258
  ::arg().set("negquery-cache-ttl", "Seconds to store negative query results in the QueryCache") = "60";
256✔
259
  ::arg().set("query-cache-ttl", "Seconds to store query results in the QueryCache") = "20";
256✔
260
  ::arg().set("zone-cache-refresh-interval", "Seconds to cache list of known zones") = "300";
256✔
261
  ::arg().set("server-id", "Returned when queried for 'id.server' TXT or NSID, defaults to hostname - disabled or custom") = "";
256✔
262
  ::arg().set("default-soa-content", "Default SOA content") = "a.misconfigured.dns.server.invalid hostmaster.@ 0 10800 3600 604800 3600";
256✔
263
  ::arg().set("default-soa-edit", "Default SOA-EDIT value") = "";
256✔
264
  ::arg().set("default-soa-edit-signed", "Default SOA-EDIT value for signed zones") = "";
256✔
265
  ::arg().set("dnssec-key-cache-ttl", "Seconds to cache DNSSEC keys from the database") = "30";
256✔
266
  ::arg().set("domain-metadata-cache-ttl", "Seconds to cache zone metadata from the database") = "";
256✔
267
  ::arg().set("zone-metadata-cache-ttl", "Seconds to cache zone metadata from the database") = "60";
256✔
268

269
  ::arg().set("trusted-notification-proxy", "IP address of incoming notification proxy") = "";
256✔
270
  ::arg().set("secondary-do-renotify", "If this secondary should send out notifications after receiving zone transfers from a primary") = "no";
256✔
271
  ::arg().set("forward-notify", "IP addresses to forward received notifications to regardless of primary or secondary settings") = "";
256✔
272

273
  ::arg().set("default-ttl", "Seconds a result is valid if not set otherwise") = "3600";
256✔
274
  ::arg().set("max-tcp-connections", "Maximum number of TCP connections") = "20";
256✔
275
  ::arg().set("max-tcp-connections-per-client", "Maximum number of simultaneous TCP connections per client") = "0";
256✔
276
  ::arg().set("max-tcp-transactions-per-conn", "Maximum number of subsequent queries per TCP connection") = "0";
256✔
277
  ::arg().set("max-tcp-connection-duration", "Maximum time in seconds that a TCP DNS connection is allowed to stay open.") = "0";
256✔
278
  ::arg().set("tcp-idle-timeout", "Maximum time in seconds that a TCP DNS connection is allowed to stay open while being idle") = "5";
256✔
279

280
  ::arg().setSwitch("no-shuffle", "Set this to prevent random shuffling of answers - for regression testing") = "off";
256✔
281

282
  ::arg().set("setuid", "If set, change user id to this uid for more security") = "";
256✔
283
  ::arg().set("setgid", "If set, change group id to this gid for more security") = "";
256✔
284

285
  ::arg().set("max-cache-entries", "Maximum number of entries in the query cache") = "1000000";
256✔
286
  ::arg().set("max-packet-cache-entries", "Maximum number of entries in the packet cache") = "1000000";
256✔
287
  ::arg().set("max-signature-cache-entries", "Maximum number of signatures cache entries") = "";
256✔
288
  ::arg().set("max-ent-entries", "Maximum number of empty non-terminals in a zone") = "100000";
256✔
289
  ::arg().set("entropy-source", "If set, read entropy from this file") = "/dev/urandom";
256✔
290

291
  ::arg().set("lua-prequery-script", "Lua script with prequery handler (DO NOT USE)") = "";
256✔
292
  ::arg().set("lua-dnsupdate-policy-script", "Lua script with DNS update policy handler") = "";
256✔
293
  ::arg().set("lua-global-include-dir", "Include *.lua files from this directory into Lua contexts") = "";
256✔
294

295
  ::arg().setSwitch("traceback-handler", "Enable the traceback handler (Linux only)") = "yes";
256✔
296
  ::arg().setSwitch("direct-dnskey", "Fetch DNSKEY, CDS and CDNSKEY RRs from backend during DNSKEY or CDS/CDNSKEY synthesis") = "no";
256✔
297
  ::arg().set("default-ksk-algorithm", "Default KSK algorithm") = "ecdsa256";
256✔
298
  ::arg().set("default-ksk-size", "Default KSK size (0 means default)") = "0";
256✔
299
  ::arg().set("default-zsk-algorithm", "Default ZSK algorithm") = "";
256✔
300
  ::arg().set("default-zsk-size", "Default ZSK size (0 means default)") = "0";
256✔
301
  ::arg().set("max-nsec3-iterations", "Limit the number of NSEC3 hash iterations") = "100";
256✔
302
  ::arg().set("default-publish-cdnskey", "Default value for PUBLISH-CDNSKEY") = "";
256✔
303
  ::arg().set("default-publish-cds", "Default value for PUBLISH-CDS") = "";
256✔
304

305
  ::arg().set("include-dir", "Include *.conf files from this directory");
256✔
306
  ::arg().set("security-poll-suffix", "Zone name from which to query security update notifications") = "secpoll.powerdns.com.";
256✔
307

308
  ::arg().setSwitch("expand-alias", "Expand ALIAS records") = "no";
256✔
309
  ::arg().set("outgoing-axfr-expand-alias", "Expand ALIAS records during outgoing AXFR") = "no";
256✔
310
  ::arg().setSwitch("8bit-dns", "Allow 8bit dns queries") = "no";
256✔
311
#ifdef HAVE_LUA_RECORDS
256✔
312
  ::arg().setSwitch("enable-lua-records", "Process LUA records for all zones (metadata overrides this)") = "no";
256✔
313
  ::arg().setSwitch("lua-records-insert-whitespace", "Insert whitespace when combining LUA chunks") = "no";
256✔
314
  ::arg().set("lua-records-exec-limit", "LUA records scripts execution limit (instructions count). Values <= 0 mean no limit") = "1000";
256✔
315
  ::arg().set("lua-health-checks-expire-delay", "Stops doing health checks after the record hasn't been used for that delay (in seconds)") = "3600";
256✔
316
  ::arg().set("lua-health-checks-interval", "LUA records health checks monitoring interval in seconds") = "5";
256✔
317
  ::arg().set("lua-consistent-hashes-cleanup-interval", "Pre-computed hashes cleanup interval (in seconds)") = "3600";
256✔
318
  ::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";
256✔
319
#endif
256✔
320
  ::arg().setSwitch("axfr-lower-serial", "Also AXFR a zone from a primary with a lower serial") = "no";
256✔
321

322
  ::arg().set("lua-axfr-script", "Script to be used to edit incoming AXFRs") = "";
256✔
323
  ::arg().set("xfr-max-received-mbytes", "Maximum number of megabytes received from an incoming XFR") = "100";
256✔
324
  ::arg().set("axfr-fetch-timeout", "Maximum time in seconds for inbound AXFR to start or be idle after starting") = "10";
256✔
325

326
  ::arg().set("tcp-fast-open", "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size") = "0";
256✔
327

328
  ::arg().set("max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file") = "0";
256✔
329
  ::arg().set("max-include-depth", "Maximum number of nested $INCLUDE directives while processing a zone file") = "20";
256✔
330
  ::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";
256✔
331
  ::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";
256✔
332

333
  ::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";
256✔
334

335
  ::arg().set("rng", "Specify the random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.") = "auto";
256✔
336

337
  ::arg().set("default-catalog-zone", "Catalog zone to assign newly created primary zones (via the API) to") = "";
256✔
338

339
#ifdef ENABLE_GSS_TSIG
256✔
340
  ::arg().setSwitch("enable-gss-tsig", "Enable GSS TSIG processing") = "no";
256✔
341
#endif
256✔
342
  ::arg().setDefaults();
256✔
343
}
256✔
344

345
static time_t s_start = time(nullptr);
346
static uint64_t uptimeOfProcess(const std::string& /* str */)
347
{
13✔
348
  return time(nullptr) - s_start;
13✔
349
}
13✔
350

351
static uint64_t getSysUserTimeMsec(const std::string& str)
352
{
18✔
353
  struct rusage ru;
18✔
354
  getrusage(RUSAGE_SELF, &ru);
18✔
355

356
  if (str == "sys-msec") {
18✔
357
    return (ru.ru_stime.tv_sec * 1000ULL + ru.ru_stime.tv_usec / 1000);
9✔
358
  }
9✔
359
  else
9✔
360
    return (ru.ru_utime.tv_sec * 1000ULL + ru.ru_utime.tv_usec / 1000);
9✔
361
}
18✔
362

363
static uint64_t getTCPConnectionCount(const std::string& /* str */)
364
{
9✔
365
  return s_tcpNameserver->numTCPConnections();
9✔
366
}
9✔
367

368
static uint64_t getQCount(const std::string& /* str */)
369
try {
9✔
370
  int totcount = 0;
9✔
371
  for (const auto& d : s_distributors) {
9✔
372
    if (!d)
9!
373
      continue;
×
374
    totcount += d->getQueueSize(); // this does locking and other things, so don't get smart
9✔
375
  }
9✔
376
  return totcount;
9✔
377
}
9✔
378
catch (std::exception& e) {
9✔
379
  g_log << Logger::Error << "Had error retrieving queue sizes: " << e.what() << endl;
×
380
  return 0;
×
381
}
×
382
catch (PDNSException& e) {
9✔
383
  g_log << Logger::Error << "Had error retrieving queue sizes: " << e.reason << endl;
×
384
  return 0;
×
385
}
×
386

387
static uint64_t getLatency(const std::string& /* str */)
388
{
13✔
389
  return round(avg_latency);
13✔
390
}
13✔
391

392
static uint64_t getReceiveLatency(const std::string& /* str */)
393
{
9✔
394
  return round(receive_latency);
9✔
395
}
9✔
396

397
static uint64_t getCacheLatency(const std::string& /* str */)
398
{
9✔
399
  return round(cache_latency);
9✔
400
}
9✔
401

402
static uint64_t getBackendLatency(const std::string& /* str */)
403
{
9✔
404
  return round(backend_latency);
9✔
405
}
9✔
406

407
static uint64_t getSendLatency(const std::string& /* str */)
408
{
9✔
409
  return round(send_latency);
9✔
410
}
9✔
411

412
static void declareStats()
413
{
159✔
414
  S.declare("udp-queries", "Number of UDP queries received");
159✔
415
  S.declare("udp-do-queries", "Number of UDP queries received with DO bit");
159✔
416
  S.declare("udp-cookie-queries", "Number of UDP queries received with the COOKIE EDNS option");
159✔
417
  S.declare("udp-answers", "Number of answers sent out over UDP");
159✔
418
  S.declare("udp-answers-bytes", "Total size of answers sent out over UDP");
159✔
419
  S.declare("udp4-answers-bytes", "Total size of answers sent out over UDPv4");
159✔
420
  S.declare("udp6-answers-bytes", "Total size of answers sent out over UDPv6");
159✔
421

422
  S.declare("udp4-answers", "Number of IPv4 answers sent out over UDP");
159✔
423
  S.declare("udp4-queries", "Number of IPv4 UDP queries received");
159✔
424
  S.declare("udp6-answers", "Number of IPv6 answers sent out over UDP");
159✔
425
  S.declare("udp6-queries", "Number of IPv6 UDP queries received");
159✔
426
  S.declare("overload-drops", "Queries dropped because backends overloaded");
159✔
427

428
  S.declare("rd-queries", "Number of recursion desired questions");
159✔
429
  S.declare("recursion-unanswered", "Number of packets unanswered by configured recursor");
159✔
430
  S.declare("recursing-answers", "Number of recursive answers sent out");
159✔
431
  S.declare("recursing-questions", "Number of questions sent to recursor");
159✔
432
  S.declare("corrupt-packets", "Number of corrupt packets received");
159✔
433
  S.declare("signatures", "Number of DNSSEC signatures made");
159✔
434
  S.declare("tcp-queries", "Number of TCP queries received");
159✔
435
  S.declare("tcp-cookie-queries", "Number of TCP queries received with the COOKIE option");
159✔
436
  S.declare("tcp-answers", "Number of answers sent out over TCP");
159✔
437
  S.declare("tcp-answers-bytes", "Total size of answers sent out over TCP");
159✔
438
  S.declare("tcp4-answers-bytes", "Total size of answers sent out over TCPv4");
159✔
439
  S.declare("tcp6-answers-bytes", "Total size of answers sent out over TCPv6");
159✔
440

441
  S.declare("tcp4-queries", "Number of IPv4 TCP queries received");
159✔
442
  S.declare("tcp4-answers", "Number of IPv4 answers sent out over TCP");
159✔
443

444
  S.declare("tcp6-queries", "Number of IPv6 TCP queries received");
159✔
445
  S.declare("tcp6-answers", "Number of IPv6 answers sent out over TCP");
159✔
446

447
  S.declare("open-tcp-connections", "Number of currently open TCP connections", getTCPConnectionCount, StatType::gauge);
159✔
448

449
  S.declare("qsize-q", "Number of questions waiting for database attention", getQCount, StatType::gauge);
159✔
450

451
  S.declare("dnsupdate-queries", "DNS update packets received.");
159✔
452
  S.declare("dnsupdate-answers", "DNS update packets successfully answered.");
159✔
453
  S.declare("dnsupdate-refused", "DNS update packets that are refused.");
159✔
454
  S.declare("dnsupdate-changes", "DNS update changes to records in total.");
159✔
455

456
  S.declare("incoming-notifications", "NOTIFY packets received.");
159✔
457

458
  S.declare("uptime", "Uptime of process in seconds", uptimeOfProcess, StatType::counter);
159✔
459
  S.declare("real-memory-usage", "Actual unique use of memory in bytes (approx)", getRealMemoryUsage, StatType::gauge);
159✔
460
  S.declare("special-memory-usage", "Actual unique use of memory in bytes (approx)", getSpecialMemoryUsage, StatType::gauge);
159✔
461
  S.declare("fd-usage", "Number of open filedescriptors", getOpenFileDescriptors, StatType::gauge);
159✔
462
#ifdef __linux__
159✔
463
  S.declare("udp-recvbuf-errors", "UDP 'recvbuf' errors", udpErrorStats, StatType::counter);
159✔
464
  S.declare("udp-sndbuf-errors", "UDP 'sndbuf' errors", udpErrorStats, StatType::counter);
159✔
465
  S.declare("udp-noport-errors", "UDP 'noport' errors", udpErrorStats, StatType::counter);
159✔
466
  S.declare("udp-in-errors", "UDP 'in' errors", udpErrorStats, StatType::counter);
159✔
467
  S.declare("udp-in-csum-errors", "UDP 'in checksum' errors", udpErrorStats, StatType::counter);
159✔
468
  S.declare("udp6-in-errors", "UDP 'in' errors over IPv6", udp6ErrorStats, StatType::counter);
159✔
469
  S.declare("udp6-recvbuf-errors", "UDP 'recvbuf' errors over IPv6", udp6ErrorStats, StatType::counter);
159✔
470
  S.declare("udp6-sndbuf-errors", "UDP 'sndbuf' errors over IPv6", udp6ErrorStats, StatType::counter);
159✔
471
  S.declare("udp6-noport-errors", "UDP 'noport' errors over IPv6", udp6ErrorStats, StatType::counter);
159✔
472
  S.declare("udp6-in-csum-errors", "UDP 'in checksum' errors over IPv6", udp6ErrorStats, StatType::counter);
159✔
473
#endif
159✔
474

475
  S.declare("sys-msec", "Number of msec spent in system time", getSysUserTimeMsec, StatType::counter);
159✔
476
  S.declare("user-msec", "Number of msec spent in user time", getSysUserTimeMsec, StatType::counter);
159✔
477

478
#ifdef __linux__
159✔
479
  S.declare("cpu-iowait", "Time spent waiting for I/O to complete by the whole system, in units of USER_HZ", getCPUIOWait, StatType::counter);
159✔
480
  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);
159✔
481
#endif
159✔
482

483
  S.declare("meta-cache-size", "Number of entries in the metadata cache", DNSSECKeeper::dbdnssecCacheSizes, StatType::gauge);
159✔
484
  S.declare("key-cache-size", "Number of entries in the key cache", DNSSECKeeper::dbdnssecCacheSizes, StatType::gauge);
159✔
485
  S.declare("signature-cache-size", "Number of entries in the signature cache", signatureCacheSize, StatType::gauge);
159✔
486

487
  S.declare("nxdomain-packets", "Number of times an NXDOMAIN packet was sent out");
159✔
488
  S.declare("noerror-packets", "Number of times a NOERROR packet was sent out");
159✔
489
  S.declare("servfail-packets", "Number of times a server-failed packet was sent out");
159✔
490
  S.declare("unauth-packets", "Number of times a zone we are not auth for was queried");
159✔
491
  S.declare("latency", "Average number of microseconds needed to answer a question", getLatency, StatType::gauge);
159✔
492
  S.declare("receive-latency", "Average number of microseconds needed to receive a query", getReceiveLatency, StatType::gauge);
159✔
493
  S.declare("cache-latency", "Average number of microseconds needed for a packet cache lookup", getCacheLatency, StatType::gauge);
159✔
494
  S.declare("backend-latency", "Average number of microseconds needed for a backend lookup", getBackendLatency, StatType::gauge);
159✔
495
  S.declare("send-latency", "Average number of microseconds needed to send the answer", getSendLatency, StatType::gauge);
159✔
496
  S.declare("timedout-packets", "Number of packets which weren't answered within timeout set");
159✔
497
  S.declare("security-status", "Security status based on regular polling", StatType::gauge);
159✔
498
  S.declare(
159✔
499
    "xfr-queue", "Size of the queue of zones to be XFRd", [](const string&) { return Communicator.getSuckRequestsWaiting(); }, StatType::gauge);
163✔
500
  S.declareDNSNameQTypeRing("queries", "UDP Queries Received");
159✔
501
  S.declareDNSNameQTypeRing("nxdomain-queries", "Queries for nonexistent records within existent zones");
159✔
502
  S.declareDNSNameQTypeRing("noerror-queries", "Queries for existing records, but for type we don't have");
159✔
503
  S.declareDNSNameQTypeRing("servfail-queries", "Queries that could not be answered due to backend errors");
159✔
504
  S.declareDNSNameQTypeRing("unauth-queries", "Queries for zones that we are not authoritative for");
159✔
505
  S.declareRing("logmessages", "Log Messages");
159✔
506
  S.declareComboRing("remotes", "Remote server IP addresses");
159✔
507
  S.declareComboRing("remotes-unauth", "Remote hosts querying zones for which we are not auth");
159✔
508
  S.declareComboRing("remotes-corrupt", "Remote hosts sending corrupt packets");
159✔
509
}
159✔
510

511
static int isGuarded(char** argv)
512
{
159✔
513
  char* p = strstr(argv[0], "-instance");
159✔
514

515
  return !!p;
159✔
516
}
159✔
517

518
static void sendout(std::unique_ptr<DNSPacket>& a, int start)
519
{
86,870✔
520
  if (!a)
86,870!
UNCOV
521
    return;
×
522

523
  try {
86,870✔
524
    int diff = a->d_dt.udiffNoReset();
86,870✔
525
    backend_latency = 0.999 * backend_latency + 0.001 * std::max(diff - start, 0);
86,870✔
526
    start = diff;
86,870✔
527

528
    s_udpNameserver->send(*a);
86,870✔
529

530
    diff = a->d_dt.udiff();
86,870✔
531
    send_latency = 0.999 * send_latency + 0.001 * std::max(diff - start, 0);
86,870✔
532

533
    avg_latency = 0.999 * avg_latency + 0.001 * std::max(diff, 0);
86,870✔
534
  }
86,870✔
535
  catch (const std::exception& e) {
86,870✔
536
    g_log << Logger::Error << "Caught unhandled exception while sending a response: " << e.what() << endl;
×
537
  }
×
538
}
86,870✔
539

540
//! The qthread receives questions over the internet via the Nameserver class, and hands them to the Distributor for further processing
541
static void qthread(unsigned int num)
542
try {
159✔
543
  setThreadName("pdns/receiver");
159✔
544

545
  s_distributors[num] = DNSDistributor::Create(::arg().asNum("distributor-threads", 1));
159✔
546
  DNSDistributor* distributor = s_distributors[num]; // the big dispatcher!
159✔
547
  DNSPacket question(true);
159✔
548
  DNSPacket cached(false);
159✔
549

550
  AtomicCounter& numreceived = *S.getPointer("udp-queries");
159✔
551
  AtomicCounter& numreceiveddo = *S.getPointer("udp-do-queries");
159✔
552
  AtomicCounter& numreceivedcookie = *S.getPointer("udp-cookie-queries");
159✔
553

554
  AtomicCounter& numreceived4 = *S.getPointer("udp4-queries");
159✔
555

556
  AtomicCounter& numreceived6 = *S.getPointer("udp6-queries");
159✔
557
  AtomicCounter& overloadDrops = *S.getPointer("overload-drops");
159✔
558

559
  int diff, start;
159✔
560
  bool logDNSQueries = ::arg().mustDo("log-dns-queries");
159✔
561
  shared_ptr<UDPNameserver> NS;
159✔
562
  std::string buffer;
159✔
563
  ComboAddress accountremote;
159✔
564

565
  // If we have SO_REUSEPORT then create a new port for all receiver threads
566
  // other than the first one.
567
  if (s_udpNameserver->canReusePort()) {
159!
568
    NS = s_udpReceivers[num];
×
569
    if (NS == nullptr) {
×
570
      NS = s_udpNameserver;
×
571
    }
×
572
  }
×
573
  else {
159✔
574
    NS = s_udpNameserver;
159✔
575
  }
159✔
576

577
  for (;;) {
97,274✔
578
    try {
97,274✔
579
      if (g_proxyProtocolACL.empty()) {
97,274!
580
        buffer.resize(DNSPacket::s_udpTruncationThreshold);
97,274✔
581
      }
97,274✔
582
      else {
×
583
        buffer.resize(DNSPacket::s_udpTruncationThreshold + g_proxyProtocolMaximumSize);
×
584
      }
×
585

586
      if (!NS->receive(question, buffer)) { // receive a packet         inline
97,274!
587
        continue; // packet was broken, try again
×
588
      }
×
589

590
      diff = question.d_dt.udiffNoReset();
97,274✔
591
      receive_latency = 0.999 * receive_latency + 0.001 * std::max(diff, 0);
97,274✔
592

593
      numreceived++;
97,274✔
594

595
      accountremote = question.d_remote;
97,274✔
596
      if (question.d_inner_remote)
97,274!
597
        accountremote = *question.d_inner_remote;
×
598

599
      if (accountremote.sin4.sin_family == AF_INET)
97,274✔
600
        numreceived4++;
97,113✔
601
      else
161✔
602
        numreceived6++;
161✔
603

604
      if (question.d_dnssecOk)
97,274✔
605
        numreceiveddo++;
88,906✔
606

607
      if (question.hasEDNSCookie())
97,274!
608
        numreceivedcookie++;
×
609

610
      if (question.d.qr)
97,274!
611
        continue;
×
612

613
      S.ringAccount("queries", question.qdomain, question.qtype);
97,274✔
614
      S.ringAccount("remotes", question.getInnerRemote());
97,274✔
615
      if (logDNSQueries) {
97,274✔
616
        g_log << Logger::Notice << "Remote " << question.getRemoteString() << " wants '" << question.qdomain << "|" << question.qtype << "', do = " << question.d_dnssecOk << ", bufsize = " << question.getMaxReplyLen();
16✔
617
        if (question.d_ednsRawPacketSizeLimit > 0 && question.getMaxReplyLen() != (unsigned int)question.d_ednsRawPacketSizeLimit)
16!
618
          g_log << " (" << question.d_ednsRawPacketSizeLimit << ")";
×
619
      }
16✔
620

621
      if (PC.enabled() && (question.d.opcode != Opcode::Notify && question.d.opcode != Opcode::Update) && question.couldBeCached()) {
97,274!
622
        start = diff;
22,264✔
623
        bool haveSomething = PC.get(question, cached); // does the PacketCache recognize this question?
22,264✔
624
        if (haveSomething) {
22,264✔
625
          if (logDNSQueries)
10,233!
626
            g_log << ": packetcache HIT" << endl;
×
627
          cached.setRemote(&question.d_remote); // inlined
10,233✔
628
          cached.d_inner_remote = question.d_inner_remote;
10,233✔
629
          cached.setSocket(question.getSocket()); // inlined
10,233✔
630
          cached.d_anyLocal = question.d_anyLocal;
10,233✔
631
          cached.setMaxReplyLen(question.getMaxReplyLen());
10,233✔
632
          cached.d.rd = question.d.rd; // copy in recursion desired bit
10,233✔
633
          cached.d.id = question.d.id;
10,233✔
634
          cached.commitD(); // commit d to the packet                        inlined
10,233✔
635

636
          diff = question.d_dt.udiffNoReset();
10,233✔
637
          cache_latency = 0.999 * cache_latency + 0.001 * std::max(diff - start, 0);
10,233✔
638
          start = diff;
10,233✔
639

640
          NS->send(cached); // answer it then                              inlined
10,233✔
641

642
          diff = question.d_dt.udiff();
10,233✔
643
          send_latency = 0.999 * send_latency + 0.001 * std::max(diff - start, 0);
10,233✔
644
          avg_latency = 0.999 * avg_latency + 0.001 * std::max(diff, 0); // 'EWMA'
10,233✔
645
          continue;
10,233✔
646
        }
10,233✔
647
        diff = question.d_dt.udiffNoReset();
12,031✔
648
        cache_latency = 0.999 * cache_latency + 0.001 * std::max(diff - start, 0);
12,031✔
649
      }
12,031✔
650

651
      if (distributor->isOverloaded()) {
87,041✔
652
        if (logDNSQueries)
1!
653
          g_log << ": Dropped query, backends are overloaded" << endl;
1✔
654
        overloadDrops++;
1✔
655
        continue;
1✔
656
      }
1✔
657

658
      if (logDNSQueries) {
87,040✔
659
        if (PC.enabled()) {
15!
660
          g_log << ": packetcache MISS" << endl;
15✔
661
        }
15✔
662
        else {
×
663
          g_log << endl;
×
664
        }
×
665
      }
15✔
666

667
      try {
87,040✔
668
        distributor->question(question, &sendout); // otherwise, give to the distributor
87,040✔
669
      }
87,040✔
670
      catch (DistributorFatal& df) { // when this happens, we have leaked loads of memory. Bailing out time.
87,040✔
671
        _exit(1);
×
672
      }
×
673
    }
87,040✔
674
    catch (const std::exception& e) {
97,274✔
675
      g_log << Logger::Error << "Caught unhandled exception in question thread: " << e.what() << endl;
×
676
    }
×
677
  }
97,274✔
678
}
159✔
679
catch (PDNSException& pe) {
159✔
680
  g_log << Logger::Error << "Fatal error in question thread: " << pe.reason << endl;
×
681
  _exit(1);
×
682
}
×
683

684
static void dummyThread()
685
{
×
686
}
×
687

688
static void triggerLoadOfLibraries()
689
{
×
690
  std::thread dummy(dummyThread);
×
691
  dummy.join();
×
692
}
×
693

694
static void mainthread()
695
{
159✔
696
  gid_t newgid = 0;
159✔
697
  if (!::arg()["setgid"].empty())
159!
698
    newgid = strToGID(::arg()["setgid"]);
×
699
  uid_t newuid = 0;
159✔
700
  if (!::arg()["setuid"].empty())
159!
701
    newuid = strToUID(::arg()["setuid"]);
×
702

703
  g_anyToTcp = ::arg().mustDo("any-to-tcp");
159✔
704
  g_8bitDNS = ::arg().mustDo("8bit-dns");
159✔
705
#ifdef HAVE_LUA_RECORDS
159✔
706
  g_doLuaRecord = ::arg().mustDo("enable-lua-records");
159✔
707
  g_LuaRecordSharedState = (::arg()["enable-lua-records"] == "shared");
159✔
708
  g_luaRecordExecLimit = ::arg().asNum("lua-records-exec-limit");
159✔
709
  g_luaRecordInsertWhitespace = ::arg().mustDo("lua-records-insert-whitespace");
159✔
710
  g_luaHealthChecksInterval = ::arg().asNum("lua-health-checks-interval");
159✔
711
  g_luaConsistentHashesExpireDelay = ::arg().asNum("lua-consistent-hashes-expire-delay");
159✔
712
  g_luaConsistentHashesCleanupInterval = ::arg().asNum("lua-consistent-hashes-cleanup-interval");
159✔
713
  g_luaHealthChecksExpireDelay = ::arg().asNum("lua-health-checks-expire-delay");
159✔
714
#endif
159✔
715
#ifdef ENABLE_GSS_TSIG
159✔
716
  g_doGssTSIG = ::arg().mustDo("enable-gss-tsig");
159✔
717
#endif
159✔
718

719
  DNSPacket::s_udpTruncationThreshold = std::max(512, ::arg().asNum("udp-truncation-threshold"));
159✔
720
  DNSPacket::s_doEDNSSubnetProcessing = ::arg().mustDo("edns-subnet-processing");
159✔
721
  PacketHandler::s_SVCAutohints = ::arg().mustDo("svc-autohints");
159✔
722

723
  g_proxyProtocolACL.toMasks(::arg()["proxy-protocol-from"]);
159✔
724
  g_proxyProtocolMaximumSize = ::arg().asNum("proxy-protocol-maximum-size");
159✔
725

726
  if (::arg()["edns-cookie-secret"].size() != 0) {
159!
727
    // User wants cookie processing
728
#ifdef HAVE_CRYPTO_SHORTHASH // we can do siphash-based cookies
×
729
    DNSPacket::s_doEDNSCookieProcessing = true;
×
730
    try {
×
731
      if (::arg()["edns-cookie-secret"].size() != EDNSCookiesOpt::EDNSCookieSecretSize) {
×
732
        throw std::range_error("wrong size (" + std::to_string(::arg()["edns-cookie-secret"].size()) + "), must be " + std::to_string(EDNSCookiesOpt::EDNSCookieSecretSize));
×
733
      }
×
734
      DNSPacket::s_EDNSCookieKey = makeBytesFromHex(::arg()["edns-cookie-secret"]);
×
735
    }
×
736
    catch (const std::range_error& e) {
×
737
      g_log << Logger::Error << "edns-cookie-secret invalid: " << e.what() << endl;
×
738
      exit(1);
×
739
    }
×
740
#else
741
    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;
742
    exit(1);
743
#endif
744
  }
×
745

746
  PC.setTTL(::arg().asNum("cache-ttl"));
159✔
747
  PC.setMaxEntries(::arg().asNum("max-packet-cache-entries"));
159✔
748
  QC.setMaxEntries(::arg().asNum("max-cache-entries"));
159✔
749
  DNSSECKeeper::setMaxEntries(::arg().asNum("max-cache-entries"));
159✔
750

751
  if (!PC.enabled() && ::arg().mustDo("log-dns-queries")) {
159!
752
    g_log << Logger::Warning << "Packet cache disabled, logging queries without HIT/MISS" << endl;
×
753
  }
×
754
  if (::arg()["outgoing-axfr-expand-alias"] == "ignore-errors") {
159!
755
    g_log << Logger::Error << "Ignoring ALIAS resolve failures on outgoing AXFR transfers, see option \"outgoing-axfr-expand-alias\"" << endl;
×
756
  }
×
757

758
  stubParseResolveConf();
159✔
759

760
  if (!::arg()["chroot"].empty()) {
159!
761
#ifdef HAVE_SYSTEMD
×
762
    char* ns;
×
763
    ns = getenv("NOTIFY_SOCKET");
×
764
    if (ns != nullptr) {
×
765
      g_log << Logger::Error << "Unable to chroot when running from systemd. Please disable chroot= or set the 'Type' for this service to 'simple'" << endl;
×
766
      exit(1);
×
767
    }
×
768
#endif
×
769
    triggerLoadOfLibraries();
×
770
    if (::arg().mustDo("primary") || ::arg().mustDo("secondary"))
×
771
      gethostbyname("a.root-servers.net"); // this forces all lookup libraries to be loaded
×
772
    Utility::dropGroupPrivs(newuid, newgid);
×
773
    if (chroot(::arg()["chroot"].c_str()) < 0 || chdir("/") < 0) {
×
774
      g_log << Logger::Error << "Unable to chroot to '" + ::arg()["chroot"] + "': " << stringerror() << ", exiting" << endl;
×
775
      exit(1);
×
776
    }
×
777
    else
×
778
      g_log << Logger::Error << "Chrooted to '" << ::arg()["chroot"] << "'" << endl;
×
779
  }
×
780
  else {
159✔
781
    Utility::dropGroupPrivs(newuid, newgid);
159✔
782
  }
159✔
783

784
  AuthWebServer webserver;
159✔
785
  Utility::dropUserPrivs(newuid);
159✔
786

787
  try {
159✔
788
    doSecPoll(true);
159✔
789
  }
159✔
790
  catch (...) {
159✔
791
  }
×
792

793
  {
159✔
794
    // Some sanity checking on default key settings
795
    bool hadKeyError = false;
159✔
796
    int kskAlgo{0}, zskAlgo{0};
159✔
797
    for (const string algotype : {"ksk", "zsk"}) {
318✔
798
      int algo, size;
318✔
799
      if (::arg()["default-" + algotype + "-algorithm"].empty())
318✔
800
        continue;
159✔
801
      algo = DNSSECKeeper::shorthand2algorithm(::arg()["default-" + algotype + "-algorithm"]);
159✔
802
      size = ::arg().asNum("default-" + algotype + "-size");
159✔
803
      if (algo == -1) {
159!
804
        g_log << Logger::Error << "Error: default-" << algotype << "-algorithm set to unknown algorithm: " << ::arg()["default-" + algotype + "-algorithm"] << endl;
×
805
        hadKeyError = true;
×
806
      }
×
807
      else if (algo <= 10 && size == 0) {
159!
808
        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;
×
809
        hadKeyError = true;
×
810
      }
×
811
      if (algotype == "ksk") {
159!
812
        kskAlgo = algo;
159✔
813
      }
159✔
814
      else {
×
815
        zskAlgo = algo;
×
816
      }
×
817
    }
159✔
818
    if (hadKeyError) {
159!
819
      exit(1);
×
820
    }
×
821
    if (kskAlgo == 0 && zskAlgo != 0) {
159!
822
      g_log << Logger::Error << "Error: default-zsk-algorithm is set, but default-ksk-algorithm is not set." << endl;
×
823
      exit(1);
×
824
    }
×
825
    if (zskAlgo != 0 && zskAlgo != kskAlgo) {
159!
826
      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;
×
827
      exit(1);
×
828
    }
×
829
  }
159✔
830

831
  pdns::parseQueryLocalAddress(::arg()["query-local-address"]);
159✔
832

833
  pdns::parseTrustedNotificationProxy(::arg()["trusted-notification-proxy"]);
159✔
834

835
  UeberBackend::go();
159✔
836

837
  // Setup the zone cache
838
  g_zoneCache.setRefreshInterval(::arg().asNum("zone-cache-refresh-interval"));
159✔
839
  try {
159✔
840
    UeberBackend B;
159✔
841
    B.updateZoneCache();
159✔
842
  }
159✔
843
  catch (PDNSException& e) {
159✔
844
    g_log << Logger::Error << "PDNSException while filling the zone cache: " << e.reason << endl;
×
845
    exit(1);
×
846
  }
×
847
  catch (std::exception& e) {
159✔
848
    g_log << Logger::Error << "STL Exception while filling the zone cache: " << e.what() << endl;
×
849
    exit(1);
×
850
  }
×
851

852
  // NOW SAFE TO CREATE THREADS!
853
  s_dynListener->go();
159✔
854

855
  if (::arg().mustDo("webserver") || ::arg().mustDo("api")) {
159✔
856
    webserver.go(S);
12✔
857
  }
12✔
858

859
  if (::arg().mustDo("primary") || ::arg().mustDo("secondary") || !::arg()["forward-notify"].empty())
159!
860
    Communicator.go();
108✔
861

862
  s_tcpNameserver->go(); // tcp nameserver launch
159✔
863

864
  unsigned int max_rthreads = ::arg().asNum("receiver-threads", 1);
159✔
865
  s_distributors.resize(max_rthreads);
159✔
866
  for (unsigned int n = 0; n < max_rthreads; ++n) {
318✔
867
    std::thread t(qthread, n);
159✔
868
    t.detach();
159✔
869
  }
159✔
870

871
  std::thread carbonThread(carbonDumpThread); // runs even w/o carbon, might change @ runtime
159✔
872

873
#ifdef HAVE_SYSTEMD
159✔
874
  /* If we are here, notify systemd that we are ay-ok! This might have some
875
   * timing issues with the backend-threads. e.g. if the initial MySQL connection
876
   * is slow and times out (leading to process termination through the backend)
877
   * We probably have told systemd already that we have started correctly.
878
   */
879
  sd_notify(0, "READY=1");
159✔
880
#endif
159✔
881

882
  const uint32_t secpollInterval = 1800;
159✔
883
  uint32_t secpollSince = 0;
159✔
884
  uint32_t zoneCacheUpdateSince = 0;
159✔
885
  for (;;) {
200✔
886
    const uint32_t sleeptime = g_zoneCache.getRefreshInterval() == 0 ? secpollInterval : std::min(secpollInterval, g_zoneCache.getRefreshInterval());
200✔
887
    sleep(sleeptime); // if any signals arrive, we might run more often than expected.
200✔
888

889
    zoneCacheUpdateSince += sleeptime;
200✔
890
    if (zoneCacheUpdateSince >= g_zoneCache.getRefreshInterval()) {
200✔
891
      try {
41✔
892
        UeberBackend B;
41✔
893
        B.updateZoneCache();
41✔
894
        zoneCacheUpdateSince = 0;
41✔
895
      }
41✔
896
      catch (PDNSException& e) {
41✔
897
        g_log << Logger::Error << "PDNSException while updating zone cache: " << e.reason << endl;
×
898
      }
×
899
      catch (std::exception& e) {
41✔
900
        g_log << Logger::Error << "STL Exception while updating zone cache: " << e.what() << endl;
×
901
      }
×
902
    }
41✔
903

904
    secpollSince += sleeptime;
200✔
905
    if (secpollSince >= secpollInterval) {
200!
906
      secpollSince = 0;
×
907
      try {
×
908
        doSecPoll(false);
×
909
      }
×
910
      catch (...) {
×
911
      }
×
912
    }
×
913
  }
200✔
914

915
  g_log << Logger::Error << "Mainthread exiting - should never happen" << endl;
159✔
916
}
159✔
917

918
static void daemonize()
919
{
×
920
  if (fork())
×
921
    exit(0); // bye bye
×
922

923
  setsid();
×
924

925
  int i = open("/dev/null", O_RDWR); /* open stdin */
×
926
  if (i < 0)
×
927
    g_log << Logger::Critical << "Unable to open /dev/null: " << stringerror() << endl;
×
928
  else {
×
929
    dup2(i, 0); /* stdin */
×
930
    dup2(i, 1); /* stderr */
×
931
    dup2(i, 2); /* stderr */
×
932
    close(i);
×
933
  }
×
934
}
×
935

936
static int cpid;
937
static void takedown(int /* i */)
938
{
×
939
  if (cpid) {
×
940
    g_log << Logger::Error << "Guardian is killed, taking down children with us" << endl;
×
941
    kill(cpid, SIGKILL);
×
942
    exit(0);
×
943
  }
×
944
}
×
945

946
static void writePid()
947
{
159✔
948
  if (!::arg().mustDo("write-pid"))
159!
949
    return;
×
950

951
  string fname = ::arg()["socket-dir"];
159✔
952
  if (::arg()["socket-dir"].empty()) {
159!
953
    if (::arg()["chroot"].empty())
×
954
      fname = std::string(LOCALSTATEDIR) + "/pdns";
×
955
    else
×
956
      fname = ::arg()["chroot"] + "/";
×
957
  }
×
958
  else if (!::arg()["socket-dir"].empty() && !::arg()["chroot"].empty()) {
159!
959
    fname = ::arg()["chroot"] + ::arg()["socket-dir"];
×
960
  }
×
961

962
  fname += +"/" + g_programname + ".pid";
159✔
963
  ofstream of(fname.c_str());
159✔
964
  if (of)
159!
965
    of << getpid() << endl;
159✔
966
  else
×
967
    g_log << Logger::Error << "Writing pid for " << getpid() << " to " << fname << " failed: " << stringerror() << endl;
×
968
}
159✔
969

970
static int g_fd1[2], g_fd2[2];
971
static FILE* g_fp;
972
static std::mutex g_guardian_lock;
973

974
// The next two methods are not in dynhandler.cc because they use a few items declared in this file.
975
static string DLCycleHandler(const vector<string>& /* parts */, pid_t /* ppid */)
976
{
×
977
  kill(cpid, SIGKILL); // why?
×
978
  kill(cpid, SIGKILL); // why?
×
979
  sleep(1);
×
980
  return "ok";
×
981
}
×
982

983
static string DLRestHandler(const vector<string>& parts, pid_t /* ppid */)
984
{
×
985
  string line;
×
986

987
  for (vector<string>::const_iterator i = parts.begin(); i != parts.end(); ++i) {
×
988
    if (i != parts.begin())
×
989
      line.append(1, ' ');
×
990
    line.append(*i);
×
991
  }
×
992
  line.append(1, '\n');
×
993

994
  std::lock_guard<std::mutex> l(g_guardian_lock);
×
995

996
  try {
×
997
    writen2(g_fd1[1], line.c_str(), line.size() + 1);
×
998
  }
×
999
  catch (PDNSException& ae) {
×
1000
    return "Error communicating with instance: " + ae.reason;
×
1001
  }
×
1002
  char mesg[512];
×
1003
  string response;
×
1004
  while (fgets(mesg, sizeof(mesg), g_fp)) {
×
1005
    if (*mesg == '\0')
×
1006
      break;
×
1007
    response += mesg;
×
1008
  }
×
1009
  boost::trim_right(response);
×
1010
  return response;
×
1011
}
×
1012

1013
static int guardian(int argc, char** argv)
1014
{
×
1015
  if (isGuarded(argv))
×
1016
    return 0;
×
1017

1018
  int infd = 0, outfd = 1;
×
1019

1020
  DynListener dlg(g_programname);
×
1021
  dlg.registerFunc("QUIT", &DLQuitHandler, "quit daemon");
×
1022
  dlg.registerFunc("CYCLE", &DLCycleHandler, "restart instance");
×
1023
  dlg.registerFunc("PING", &DLPingHandler, "ping guardian");
×
1024
  dlg.registerFunc("STATUS", &DLStatusHandler, "get instance status from guardian");
×
1025
  dlg.registerRestFunc(&DLRestHandler);
×
1026
  dlg.go();
×
1027
  string progname = argv[0];
×
1028

1029
  bool first = true;
×
1030
  cpid = 0;
×
1031

1032
  g_guardian_lock.lock();
×
1033

1034
  for (;;) {
×
1035
    int pid;
×
1036
    setStatus("Launching child");
×
1037

1038
    if (pipe(g_fd1) < 0 || pipe(g_fd2) < 0) {
×
1039
      g_log << Logger::Critical << "Unable to open pipe for coprocess: " << stringerror() << endl;
×
1040
      exit(1);
×
1041
    }
×
1042

1043
    if (!(g_fp = fdopen(g_fd2[0], "r"))) {
×
1044
      g_log << Logger::Critical << "Unable to associate a file pointer with pipe: " << stringerror() << endl;
×
1045
      exit(1);
×
1046
    }
×
1047
    setbuf(g_fp, nullptr); // no buffering please, confuses select
×
1048

1049
    if (!(pid = fork())) { // child
×
1050
      signal(SIGTERM, SIG_DFL);
×
1051

1052
      signal(SIGHUP, SIG_DFL);
×
1053
      signal(SIGUSR1, SIG_DFL);
×
1054
      signal(SIGUSR2, SIG_DFL);
×
1055

1056
      char** const newargv = new char*[argc + 2];
×
1057
      int n;
×
1058

1059
      if (::arg()["config-name"] != "") {
×
1060
        progname += "-" + ::arg()["config-name"];
×
1061
        g_log << Logger::Error << "Virtual configuration name: " << ::arg()["config-name"] << endl;
×
1062
      }
×
1063

1064
      newargv[0] = strdup(const_cast<char*>((progname + "-instance").c_str()));
×
1065
      for (n = 1; n < argc; n++) {
×
1066
        newargv[n] = argv[n];
×
1067
      }
×
1068
      newargv[n] = nullptr;
×
1069

1070
      g_log << Logger::Error << "Guardian is launching an instance" << endl;
×
1071
      close(g_fd1[1]);
×
1072
      fclose(g_fp); // this closes g_fd2[0] for us
×
1073

1074
      if (g_fd1[0] != infd) {
×
1075
        dup2(g_fd1[0], infd);
×
1076
        close(g_fd1[0]);
×
1077
      }
×
1078

1079
      if (g_fd2[1] != outfd) {
×
1080
        dup2(g_fd2[1], outfd);
×
1081
        close(g_fd2[1]);
×
1082
      }
×
1083
      if (execvp(argv[0], newargv) < 0) {
×
1084
        g_log << Logger::Error << "Unable to execvp '" << argv[0] << "': " << stringerror() << endl;
×
1085
        char** p = newargv;
×
1086
        while (*p)
×
1087
          g_log << Logger::Error << *p++ << endl;
×
1088

1089
        exit(1);
×
1090
      }
×
1091
      g_log << Logger::Error << "execvp returned!!" << endl;
×
1092
      // never reached
1093
    }
×
1094
    else if (pid > 0) { // parent
×
1095
      close(g_fd1[0]);
×
1096
      close(g_fd2[1]);
×
1097

1098
      if (first) {
×
1099
        first = false;
×
1100
        signal(SIGTERM, takedown);
×
1101

1102
        signal(SIGHUP, SIG_IGN);
×
1103
        signal(SIGUSR1, SIG_IGN);
×
1104
        signal(SIGUSR2, SIG_IGN);
×
1105

1106
        writePid();
×
1107
      }
×
1108
      g_guardian_lock.unlock();
×
1109
      int status;
×
1110
      cpid = pid;
×
1111
      for (;;) {
×
1112
        int ret = waitpid(pid, &status, WNOHANG);
×
1113

1114
        if (ret < 0) {
×
1115
          g_log << Logger::Error << "In guardian loop, waitpid returned error: " << stringerror() << endl;
×
1116
          g_log << Logger::Error << "Dying" << endl;
×
1117
          exit(1);
×
1118
        }
×
1119
        else if (ret) // something exited
×
1120
          break;
×
1121
        else { // child is alive
×
1122
          // execute some kind of ping here
1123
          if (DLQuitPlease())
×
1124
            takedown(1); // needs a parameter..
×
1125
          setStatus("Child running on pid " + std::to_string(pid));
×
1126
          sleep(1);
×
1127
        }
×
1128
      }
×
1129

1130
      g_guardian_lock.lock();
×
1131
      close(g_fd1[1]);
×
1132
      fclose(g_fp);
×
1133
      g_fp = nullptr;
×
1134

1135
      if (WIFEXITED(status)) {
×
1136
        int ret = WEXITSTATUS(status);
×
1137

1138
        if (ret == 99) {
×
1139
          g_log << Logger::Error << "Child requested a stop, exiting" << endl;
×
1140
          exit(1);
×
1141
        }
×
1142
        setStatus("Child died with code " + std::to_string(ret));
×
1143
        g_log << Logger::Error << "Our pdns instance exited with code " << ret << ", respawning" << endl;
×
1144

1145
        sleep(1);
×
1146
        continue;
×
1147
      }
×
1148
      if (WIFSIGNALED(status)) {
×
1149
        int sig = WTERMSIG(status);
×
1150
        setStatus("Child died because of signal " + std::to_string(sig));
×
1151
        g_log << Logger::Error << "Our pdns instance (" << pid << ") exited after signal " << sig << endl;
×
1152
#ifdef WCOREDUMP
×
1153
        if (WCOREDUMP(status))
×
1154
          g_log << Logger::Error << "Dumped core" << endl;
×
1155
#endif
×
1156

1157
        g_log << Logger::Error << "Respawning" << endl;
×
1158
        sleep(1);
×
1159
        continue;
×
1160
      }
×
1161
      g_log << Logger::Error << "No clue what happened! Respawning" << endl;
×
1162
    }
×
1163
    else {
×
1164
      g_log << Logger::Error << "Unable to fork: " << stringerror() << endl;
×
1165
      exit(1);
×
1166
    }
×
1167
  }
×
1168
}
×
1169

1170
#if defined(__GLIBC__) && !defined(__UCLIBC__)
1171
#include <execinfo.h>
1172
static void tbhandler(int num)
1173
{
×
1174
  g_log << Logger::Critical << "Got a signal " << num << ", attempting to print trace: " << endl;
×
1175
  void* array[20]; // only care about last 17 functions (3 taken with tracing support)
×
1176
  size_t size;
×
1177
  char** strings;
×
1178
  size_t i;
×
1179

1180
  size = backtrace(array, 20);
×
1181
  strings = backtrace_symbols(array, size); // Need -rdynamic gcc (linker) flag for this to work
×
1182

1183
  for (i = 0; i < size; i++) // skip useless functions
×
1184
    g_log << Logger::Error << strings[i] << endl;
×
1185

1186
  signal(SIGABRT, SIG_DFL);
×
1187
  abort(); // hopefully will give core
×
1188
}
×
1189
#endif
1190

1191
#ifdef COVERAGE
1192
static void sigTermHandler([[maybe_unused]] int signal)
1193
{
159✔
1194
  pdns::coverage::dumpCoverageData();
159✔
1195
  _exit(EXIT_SUCCESS);
159✔
1196
}
159✔
1197
#endif /* COVERAGE */
1198

1199
//! The main function of pdns, the pdns process
1200
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
1201
int main(int argc, char** argv)
1202
{
256✔
1203
  versionSetProduct(ProductAuthoritative);
256✔
1204
  reportAllTypes(); // init MOADNSParser
256✔
1205

1206
  g_programname = "pdns";
256✔
1207
  g_starttime = time(nullptr);
256✔
1208

1209
#if defined(__GLIBC__) && !defined(__UCLIBC__)
256✔
1210
  signal(SIGSEGV, tbhandler);
256✔
1211
  signal(SIGFPE, tbhandler);
256✔
1212
  signal(SIGABRT, tbhandler);
256✔
1213
  signal(SIGILL, tbhandler);
256✔
1214
#endif
256✔
1215

1216
  std::ios_base::sync_with_stdio(false);
256✔
1217

1218
  g_log.toConsole(Logger::Warning);
256✔
1219
  try {
256✔
1220
    declareArguments();
256✔
1221

1222
    ::arg().laxParse(argc, argv); // do a lax parse
256✔
1223

1224
    if (::arg().mustDo("version")) {
256✔
1225
      cout << getProductVersion();
97✔
1226
      cout << getBuildConfiguration();
97✔
1227
      return 0;
97✔
1228
    }
97✔
1229

1230
    if (::arg()["config-name"] != "")
159✔
1231
      g_programname += "-" + ::arg()["config-name"];
134✔
1232

1233
    g_log.setName(g_programname);
159✔
1234

1235
    string configname = ::arg()["config-dir"] + "/" + g_programname + ".conf";
159✔
1236
    cleanSlashes(configname);
159✔
1237

1238
    if (::arg()["config"] != "default" && !::arg().mustDo("no-config")) // "config" == print a configuration file
159!
1239
      ::arg().laxFile(configname.c_str());
132✔
1240

1241
    ::arg().laxParse(argc, argv); // reparse so the commandline still wins
159✔
1242
    if (!::arg()["logging-facility"].empty()) {
159!
1243
      int val = logFacilityToLOG(::arg().asNum("logging-facility"));
1244
      if (val >= 0)
×
1245
        g_log.setFacility(val);
1246
      else
1247
        g_log << Logger::Error << "Unknown logging facility " << ::arg().asNum("logging-facility") << endl;
1248
    }
1249

1250
    if (!::arg().isEmpty("domain-metadata-cache-ttl"))
159✔
1251
      ::arg().set("zone-metadata-cache-ttl") = ::arg()["domain-metadata-cache-ttl"];
1✔
1252

1253
    // this mirroring back is on purpose, so that config dumps reflect the actual setting on both names
1254
    ::arg().set("domain-metadata-cache-ttl") = ::arg()["zone-metadata-cache-ttl"];
159✔
1255

1256
    g_log.setLoglevel((Logger::Urgency)(::arg().asNum("loglevel")));
159✔
1257
    g_log.setPrefixed(::arg().mustDo("loglevel-show"));
159✔
1258
    g_log.disableSyslog(::arg().mustDo("disable-syslog"));
159✔
1259
    g_log.setTimestamps(::arg().mustDo("log-timestamp"));
159✔
1260
    g_log.toConsole((Logger::Urgency)(::arg().asNum("loglevel")));
159✔
1261

1262
    if (::arg().mustDo("help") || ::arg().mustDo("config")) {
159!
1263
      ::arg().set("daemon") = "no";
1264
      ::arg().set("guardian") = "no";
1265
    }
1266

1267
    if (::arg().mustDo("guardian") && !isGuarded(argv)) {
159!
1268
      if (::arg().mustDo("daemon")) {
×
1269
        g_log.toConsole(Logger::Critical);
1270
        daemonize();
1271
      }
1272
      guardian(argc, argv);
1273
      // never get here, guardian will reinvoke process
1274
      cerr << "Um, we did get here!" << endl;
1275
    }
1276

1277
#ifdef COVERAGE
159✔
1278
    if (!::arg().mustDo("guardian") && !::arg().mustDo("daemon")) {
159!
1279
      signal(SIGTERM, sigTermHandler);
159✔
1280
    }
159✔
1281
#endif
159✔
1282

1283
    // we really need to do work - either standalone or as an instance
1284

1285
#if defined(__GLIBC__) && !defined(__UCLIBC__)
159✔
1286
    if (!::arg().mustDo("traceback-handler")) {
159!
1287
      g_log << Logger::Warning << "Disabling traceback handler" << endl;
1288
      signal(SIGSEGV, SIG_DFL);
1289
      signal(SIGFPE, SIG_DFL);
1290
      signal(SIGABRT, SIG_DFL);
1291
      signal(SIGILL, SIG_DFL);
1292
    }
1293
#endif
159✔
1294

1295
#ifdef HAVE_LIBSODIUM
159✔
1296
    if (sodium_init() == -1) {
159!
1297
      cerr << "Unable to initialize sodium crypto library" << endl;
1298
      exit(99);
1299
    }
1300
#endif
159✔
1301

1302
    openssl_thread_setup();
159✔
1303
    openssl_seed();
159✔
1304

1305
#ifdef HAVE_LUA_RECORDS
159✔
1306
    MiniCurl::init();
159✔
1307
#endif /* HAVE_LUA_RECORDS */
159✔
1308

1309
    if (!::arg()["load-modules"].empty()) {
159!
1310
      vector<string> modules;
1311

1312
      stringtok(modules, ::arg()["load-modules"], ", ");
1313
      if (!UeberBackend::loadModules(modules, ::arg()["module-dir"])) {
×
1314
        exit(1);
1315
      }
1316
    }
1317

1318
    BackendMakers().launch(::arg()["launch"]); // vrooooom!
159✔
1319

1320
    if (!::arg().getCommands().empty()) {
159!
1321
      cerr << "Fatal: non-option";
1322
      if (::arg().getCommands().size() > 1) {
×
1323
        cerr << "s";
1324
      }
1325
      cerr << " (";
1326
      bool first = true;
1327
      for (const auto& c : ::arg().getCommands()) {
×
1328
        if (!first) {
×
1329
          cerr << ", ";
1330
        }
1331
        first = false;
1332
        cerr << c;
1333
      }
1334
      cerr << ") on the command line, perhaps a '--setting=123' statement missed the '='?" << endl;
1335
      exit(99);
1336
    }
1337

1338
    if (::arg().mustDo("help")) {
159!
1339
      cout << "syntax:" << endl
1340
           << endl;
1341
      cout << ::arg().helpstring(::arg()["help"]) << endl;
1342
      exit(0);
1343
    }
1344

1345
    if (::arg().mustDo("config")) {
159!
1346
      string config = ::arg()["config"];
1347
      if (config == "default") {
×
1348
        cout << ::arg().configstring(false, true);
1349
      }
1350
      else if (config == "diff") {
×
1351
        cout << ::arg().configstring(true, false);
1352
      }
1353
      else if (config == "check") {
×
1354
        try {
1355
          if (!::arg().mustDo("no-config"))
×
1356
            ::arg().file(configname.c_str());
1357
          ::arg().parse(argc, argv);
1358
          exit(0);
1359
        }
1360
        catch (const ArgException& A) {
1361
          cerr << "Fatal error: " << A.reason << endl;
1362
          exit(1);
1363
        }
1364
      }
1365
      else {
1366
        cout << ::arg().configstring(true, true);
1367
      }
1368
      exit(0);
1369
    }
1370

1371
    if (::arg().mustDo("list-modules")) {
159!
1372
      auto modules = BackendMakers().getModules();
1373
      cout << "Modules available:" << endl;
1374
      for (const auto& m : modules)
×
1375
        cout << m << endl;
1376

1377
      _exit(99);
1378
    }
1379

1380
    if (!::arg().asNum("local-port")) {
159!
1381
      g_log << Logger::Error << "Unable to launch, binding to no port or port 0 makes no sense" << endl;
1382
      exit(99); // this isn't going to fix itself either
1383
    }
1384
    if (!BackendMakers().numLauncheable()) {
159!
1385
      g_log << Logger::Error << "Unable to launch, no backends configured for querying" << endl;
1386
      exit(99); // this isn't going to fix itself either
1387
    }
1388
    if (::arg().mustDo("daemon")) {
159!
1389
      g_log.toConsole(Logger::None);
1390
      if (!isGuarded(argv))
×
1391
        daemonize();
1392
    }
1393

1394
    if (isGuarded(argv)) {
159!
1395
      g_log << Logger::Warning << "This is a guarded instance of pdns" << endl;
1396
      s_dynListener = std::make_unique<DynListener>(); // listens on stdin
1397
    }
1398
    else {
159✔
1399
      g_log << Logger::Warning << "This is a standalone pdns" << endl;
159✔
1400

1401
      if (::arg().mustDo("control-console"))
159!
1402
        s_dynListener = std::make_unique<DynListener>();
1403
      else
159✔
1404
        s_dynListener = std::make_unique<DynListener>(g_programname);
159✔
1405

1406
      writePid();
159✔
1407
    }
159✔
1408
    DynListener::registerFunc("SHOW", &DLShowHandler, "show a specific statistic or * to get a list", "<statistic>");
159✔
1409
    DynListener::registerFunc("RPING", &DLPingHandler, "ping instance");
159✔
1410
    DynListener::registerFunc("QUIT", &DLRQuitHandler, "quit daemon");
159✔
1411
    DynListener::registerFunc("UPTIME", &DLUptimeHandler, "get instance uptime");
159✔
1412
    DynListener::registerFunc("NOTIFY-HOST", &DLNotifyHostHandler, "notify host for specific zone", "<zone> <host>");
159✔
1413
    DynListener::registerFunc("NOTIFY", &DLNotifyHandler, "queue a notification", "<zone>");
159✔
1414
    DynListener::registerFunc("RELOAD", &DLReloadHandler, "reload all zones");
159✔
1415
    DynListener::registerFunc("REDISCOVER", &DLRediscoverHandler, "discover any new zones");
159✔
1416
    DynListener::registerFunc("VERSION", &DLVersionHandler, "get instance version");
159✔
1417
    DynListener::registerFunc("PURGE", &DLPurgeHandler, "purge entries from packet cache", "[<record>]");
159✔
1418
    DynListener::registerFunc("CCOUNTS", &DLCCHandler, "get cache statistics");
159✔
1419
    DynListener::registerFunc("QTYPES", &DLQTypesHandler, "get QType statistics");
159✔
1420
    DynListener::registerFunc("RESPSIZES", &DLRSizesHandler, "get histogram of response sizes");
159✔
1421
    DynListener::registerFunc("REMOTES", &DLRemotesHandler, "get top remotes");
159✔
1422
    DynListener::registerFunc("SET", &DLSettingsHandler, "set config variables", "<var> <value>");
159✔
1423
    DynListener::registerFunc("RETRIEVE", &DLNotifyRetrieveHandler, "retrieve secondary zone", "<zone> [<ip>]");
159✔
1424
    DynListener::registerFunc("CURRENT-CONFIG", &DLCurrentConfigHandler, "retrieve the current configuration", "[diff]");
159✔
1425
    DynListener::registerFunc("LIST-ZONES", &DLListZones, "show list of zones", "[primary|secondary|native|consumer|producer]");
159✔
1426
    DynListener::registerFunc("TOKEN-LOGIN", &DLTokenLogin, "Login to a PKCS#11 token", "<module> <slot> <pin>");
159✔
1427
    DynListener::registerFunc("XFR-QUEUE", &DLSuckRequests, "Get all requests for XFR in queue");
159✔
1428

1429
    if (!::arg()["tcp-control-address"].empty()) {
159!
1430
      DynListener* dlTCP = new DynListener(ComboAddress(::arg()["tcp-control-address"], ::arg().asNum("tcp-control-port")));
1431
      dlTCP->go();
1432
    }
1433

1434
    // reparse, with error checking
1435
    if (!::arg().mustDo("no-config"))
159✔
1436
      ::arg().file(configname.c_str());
132✔
1437
    ::arg().parse(argc, argv);
159✔
1438

1439
    if (::arg()["server-id"].empty()) {
159!
1440
      char tmp[128];
159✔
1441
      if (gethostname(tmp, sizeof(tmp) - 1) == 0) {
159!
1442
        ::arg().set("server-id") = tmp;
159✔
1443
      }
159✔
1444
      else {
1445
        g_log << Logger::Warning << "Unable to get the hostname, NSID and id.server values will be empty: " << stringerror() << endl;
1446
      }
1447
    }
159✔
1448

1449
    s_udpNameserver = std::make_shared<UDPNameserver>(); // this fails when we are not root, throws exception
159✔
1450
    s_udpReceivers.push_back(s_udpNameserver);
159✔
1451

1452
    size_t rthreads = ::arg().asNum("receiver-threads", 1);
159✔
1453
    if (rthreads > 1 && s_udpNameserver->canReusePort()) {
159!
1454
      s_udpReceivers.resize(rthreads);
1455

1456
      for (size_t idx = 1; idx < rthreads; idx++) {
×
1457
        try {
1458
          s_udpReceivers[idx] = std::make_shared<UDPNameserver>(true);
1459
        }
1460
        catch (const PDNSException& e) {
1461
          g_log << Logger::Error << "Unable to reuse port, falling back to original bind" << endl;
1462
          break;
1463
        }
1464
      }
1465
    }
1466

1467
    s_tcpNameserver = make_unique<TCPNameserver>();
159✔
1468
  }
159✔
1469
  catch (const ArgException& A) {
256✔
1470
    g_log << Logger::Error << "Fatal error: " << A.reason << endl;
1471
    exit(1);
1472
  }
1473
  catch (const std::exception& e) {
256✔
1474
    g_log << Logger::Error << "Fatal error: " << e.what() << endl;
1475
    exit(1);
1476
  }
1477

1478
  try {
159✔
1479
    declareStats();
159✔
1480
  }
159✔
1481
  catch (const PDNSException& PE) {
159✔
1482
    g_log << Logger::Error << "Exiting because: " << PE.reason << endl;
1483
    exit(1);
1484
  }
1485

1486
  try {
159✔
1487
    auto defaultCatalog = ::arg()["default-catalog-zone"];
159✔
1488
    if (!defaultCatalog.empty()) {
159✔
1489
      auto defCatalog = DNSName(defaultCatalog);
4✔
1490
    }
4✔
1491
  }
159✔
1492
  catch (const std::exception& e) {
159✔
1493
    g_log << Logger::Error << "Invalid value '" << ::arg()["default-catalog-zone"] << "' for default-catalog-zone: " << e.what() << endl;
1494
    exit(1);
1495
  }
1496
  S.blacklist("special-memory-usage");
159✔
1497

1498
  DLOG(g_log << Logger::Warning << "Verbose logging in effect" << endl);
159✔
1499

1500
  for (const string& line : getProductVersionLines()) {
477✔
1501
    g_log << Logger::Info << line << endl;
477✔
1502
  }
477✔
1503

1504
  try {
159✔
1505
    mainthread();
159✔
1506
  }
159✔
1507
  catch (const PDNSException& e) {
159✔
1508
    try {
1509
      if (!::arg().mustDo("daemon")) {
×
1510
        cerr << "Exiting because: " << e.reason << endl;
1511
      }
1512
    }
1513
    catch (const ArgException& A) {
1514
    }
1515
    g_log << Logger::Error << "Exiting because: " << e.reason << endl;
1516
  }
1517
  catch (const std::exception& e) {
159✔
1518
    try {
1519
      if (!::arg().mustDo("daemon")) {
×
1520
        cerr << "Exiting because of STL error: " << e.what() << endl;
1521
      }
1522
    }
1523
    catch (const ArgException& A) {
1524
    }
1525
    g_log << Logger::Error << "Exiting because of STL error: " << e.what() << endl;
1526
  }
1527
  catch (...) {
159✔
1528
    cerr << "Uncaught exception of unknown type - sorry" << endl;
1529
  }
1530

1531
  exit(1);
159✔
1532
}
159✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc