]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dynhandler.cc
Merge pull request #8223 from PowerDNS/omoerbeek-patch-1
[thirdparty/pdns.git] / pdns / dynhandler.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
bf269e28
RG
25#include "auth-caches.hh"
26#include "auth-querycache.hh"
27#include "auth-packetcache.hh"
bd11bd1d 28#include "utility.hh"
12c86877
BH
29#include "dynhandler.hh"
30#include "statbag.hh"
31#include "logger.hh"
32#include "dns.hh"
33#include "arguments.hh"
34#include <signal.h>
bd11bd1d 35#include "misc.hh"
12c86877 36#include "communicator.hh"
627d2ca2 37#include "dnsseckeeper.hh"
ba7244a5 38#include "nameserver.hh"
09425ce1 39#include "responsestats.hh"
767da1a0 40#include "ueberbackend.hh"
3e8216c8 41#include "common_startup.hh"
09425ce1
F
42
43extern ResponseStats g_rs;
12c86877
BH
44
45static bool s_pleasequit;
64bcb6be 46static string d_status;
12c86877
BH
47
48bool DLQuitPlease()
49{
50 return s_pleasequit;
51}
52
53string DLQuitHandler(const vector<string>&parts, Utility::pid_t ppid)
54{
55 string ret="No return value";
56 if(parts[0]=="QUIT") {
57 s_pleasequit=true;
58 ret="Scheduling exit";
e6a9dde5 59 g_log<<Logger::Error<<"Scheduling exit on remote request"<<endl;
12c86877
BH
60 }
61 return ret;
12c86877
BH
62}
63
64static void dokill(int)
65{
e7f0140b 66 exit(0);
12c86877
BH
67}
68
64bcb6be
RA
69string DLCurrentConfigHandler(const vector<string>&parts, Utility::pid_t ppid)
70{
71 return ::arg().configstring(true);
72}
73
12c86877
BH
74string DLRQuitHandler(const vector<string>&parts, Utility::pid_t ppid)
75{
12c86877 76 signal(SIGALRM, dokill);
12c86877 77 alarm(1);
12c86877
BH
78 return "Exiting";
79}
80
81string DLPingHandler(const vector<string>&parts, Utility::pid_t ppid)
82{
83 return "PONG";
84}
85
28c3cc11 86string DLShowHandler(const vector<string>&parts, Utility::pid_t ppid) {
28c3cc11
OM
87 try {
88 extern StatBag S;
89 string ret("Wrong number of parameters");
90 if (parts.size() == 2) {
91 if (parts[1] == "*")
f3245c8c 92 ret = S.directory();
28c3cc11
OM
93 else
94 ret = S.getValueStr(parts[1]);
95 }
12c86877 96
28c3cc11
OM
97 return ret;
98 }
99 catch (...) {
100 return "Unknown";
101 }
02feff9f 102}
12c86877
BH
103
104void setStatus(const string &str)
105{
106 d_status=str;
107}
108
109string DLStatusHandler(const vector<string>&parts, Utility::pid_t ppid)
110{
111 ostringstream os;
112 os<<ppid<<": "<<d_status;
113 return os.str();
114}
115
116string DLUptimeHandler(const vector<string>&parts, Utility::pid_t ppid)
117{
118 ostringstream os;
119 os<<humanDuration(time(0)-s_starttime);
120 return os.str();
121}
122
123string DLPurgeHandler(const vector<string>&parts, Utility::pid_t ppid)
124{
627d2ca2 125 DNSSECKeeper dk;
12c86877 126 ostringstream os;
27fdc3fc 127 int ret=0;
12c86877 128
27fdc3fc
BH
129 if(parts.size()>1) {
130 for (vector<string>::const_iterator i=++parts.begin();i<parts.end();++i) {
bf269e28 131 ret+=purgeAuthCaches(*i);
478748c3 132 if(!boost::ends_with(*i, "$"))
133 dk.clearCaches(DNSName(*i));
134 else
135 dk.clearAllCaches(); // at least we do what we promise.. and a bit more!
27fdc3fc
BH
136 }
137 }
627d2ca2 138 else {
bf269e28 139 ret = purgeAuthCaches();
627d2ca2
PD
140 dk.clearAllCaches();
141 }
142
12c86877
BH
143 os<<ret;
144 return os.str();
145}
146
147string DLCCHandler(const vector<string>&parts, Utility::pid_t ppid)
148{
bf269e28
RG
149 extern AuthPacketCache PC;
150 extern AuthQueryCache QC;
151 map<char,uint64_t> counts=QC.getCounts();
152 uint64_t packetEntries = PC.size();
12c86877
BH
153 ostringstream os;
154 bool first=true;
bf269e28 155 for(map<char,uint64_t>::const_iterator i=counts.begin();i!=counts.end();++i) {
12c86877
BH
156 if(!first)
157 os<<", ";
158 first=false;
159
160 if(i->first=='!')
161 os<<"negative queries: ";
162 else if(i->first=='Q')
163 os<<"queries: ";
12c86877
BH
164 else
165 os<<"unknown: ";
166
167 os<<i->second;
168 }
bf269e28 169 os<<"packets: "<<packetEntries;
12c86877
BH
170
171 return os.str();
172}
173
ba7244a5
PD
174string DLQTypesHandler(const vector<string>&parts, Utility::pid_t ppid)
175{
09425ce1 176 return g_rs.getQTypeReport();
ba7244a5 177}
12c86877 178
93698ef3
PD
179string DLRSizesHandler(const vector<string>&parts, Utility::pid_t ppid)
180{
181 typedef map<uint16_t, uint64_t> respsizes_t;
182 respsizes_t respsizes = g_rs.getSizeResponseCounts();
183 ostringstream os;
184 boost::format fmt("%d\t%d\n");
ef7cd021 185 for(const respsizes_t::value_type& val : respsizes) {
93698ef3
PD
186 os << (fmt % val.first % val.second).str();
187 }
188 return os.str();
189}
190
191string DLRemotesHandler(const vector<string>&parts, Utility::pid_t ppid)
192{
193 extern StatBag S;
194 typedef vector<pair<string, unsigned int> > totals_t;
195 totals_t totals = S.getRing("remotes");
196 string ret;
197 boost::format fmt("%s\t%d\n");
ef7cd021 198 for(totals_t::value_type& val : totals) {
93698ef3
PD
199 ret += (fmt % val.first % val.second).str();
200 }
201 return ret;
202}
203
12c86877
BH
204string DLSettingsHandler(const vector<string>&parts, Utility::pid_t ppid)
205{
206 static const char *whitelist[]={"query-logging",0};
207 const char **p;
208
209 if(parts.size()!=3) {
210 return "Syntax: set variable value";
211 }
212
213 for(p=whitelist;*p;p++)
214 if(*p==parts[1])
215 break;
3120733f 216 if(*p) {
379ab445 217 ::arg().set(parts[1])=parts[2];
12c86877
BH
218 return "done";
219 }
220 else
3120733f 221 return "This setting cannot be changed at runtime, or no such setting";
12c86877
BH
222
223}
224
12c86877
BH
225string DLVersionHandler(const vector<string>&parts, Utility::pid_t ppid)
226{
12c86877
BH
227 return VERSION;
228}
229
ef1d2f44
BH
230string DLNotifyRetrieveHandler(const vector<string>&parts, Utility::pid_t ppid)
231{
232 extern CommunicatorClass Communicator;
233 ostringstream os;
234 if(parts.size()!=2)
235 return "syntax: retrieve domain";
236
63faa7c9
CH
237 DNSName domain;
238 try {
239 domain = DNSName(parts[1]);
240 } catch (...) {
241 return "Failed to parse domain as valid DNS name";
242 }
243
ef1d2f44 244 DomainInfo di;
295c4a00 245 UeberBackend B;
63faa7c9
CH
246 if(!B.getDomainInfo(domain, di))
247 return "Domain '"+domain.toString()+"' unknown";
ef1d2f44 248
889500d7 249 if(di.kind != DomainInfo::Slave || di.masters.empty())
63faa7c9 250 return "Domain '"+domain.toString()+"' is not a slave domain (or has no master defined)";
f2c11a48 251
e5b11b2f 252 random_shuffle(di.masters.begin(), di.masters.end());
d3ee36f2 253 Communicator.addSuckRequest(domain, di.masters.front());
9b0f144f 254 return "Added retrieval request for '"+domain.toString()+"' from master "+di.masters.front().toLogString();
ef1d2f44 255}
12c86877
BH
256
257string DLNotifyHostHandler(const vector<string>&parts, Utility::pid_t ppid)
258{
259 extern CommunicatorClass Communicator;
260 ostringstream os;
261 if(parts.size()!=3)
ea44d9d3 262 return "syntax: notify-host domain ip";
0c541891 263 if(!::arg().mustDo("master") && !(::arg().mustDo("slave") && ::arg().mustDo("slave-renotify")))
aef133df 264 return "PowerDNS not configured as master or slave with re-notifications";
5762f14e 265
c1a295ca
CH
266 DNSName domain;
267 try {
268 domain = DNSName(parts[1]);
269 } catch (...) {
270 return "Failed to parse domain as valid DNS name";
271 }
272
c069c1f2
BH
273 try {
274 ComboAddress ca(parts[2]);
275 } catch(...)
276 {
5762f14e 277 return "Unable to convert '"+parts[2]+"' to an IP address";
c069c1f2
BH
278 }
279
e6a9dde5 280 g_log<<Logger::Warning<<"Notification request to host "<<parts[2]<<" for domain '"<<domain<<"' received from operator"<<endl;
c1a295ca 281 Communicator.notify(domain, parts[2]);
12c86877
BH
282 return "Added to queue";
283}
284
285string DLNotifyHandler(const vector<string>&parts, Utility::pid_t ppid)
286{
287 extern CommunicatorClass Communicator;
f1b4b713 288 UeberBackend B;
12c86877
BH
289 if(parts.size()!=2)
290 return "syntax: notify domain";
0c541891 291 if(!::arg().mustDo("master") && !(::arg().mustDo("slave") && ::arg().mustDo("slave-renotify")))
aef133df 292 return "PowerDNS not configured as master or slave with re-notifications";
e6a9dde5 293 g_log<<Logger::Warning<<"Notification request for domain '"<<parts[1]<<"' received from operator"<<endl;
f1b4b713
KM
294
295 if (parts[1] == "*") {
296 vector<DomainInfo> domains;
297 B.getAllDomains(&domains);
298
299 int total = 0;
300 int notified = 0;
be207d3d 301 for (const auto& di : domains) {
472dcfac 302 if (di.kind == DomainInfo::Master || di.kind == DomainInfo::Slave) { // MASTER and Slave if slave-renotify is enabled
f1b4b713 303 total++;
cb167afd 304 if(Communicator.notifyDomain(di.zone))
f1b4b713
KM
305 notified++;
306 }
307 }
308
309 if (total != notified)
310 return itoa(notified)+" out of "+itoa(total)+" zones added to queue - see log";
ec7849d4 311 return "Added "+itoa(total)+" MASTER/SLAVE zones to queue";
f1b4b713 312 } else {
100cf78b
CH
313 DNSName domain;
314 try {
315 domain = DNSName(parts[1]);
316 } catch (...) {
317 return "Failed to parse domain as valid DNS name";
318 }
290a083d 319 if(!Communicator.notifyDomain(DNSName(parts[1])))
f1b4b713
KM
320 return "Failed to add to the queue - see log";
321 return "Added to queue";
322 }
12c86877
BH
323}
324
325string DLRediscoverHandler(const vector<string>&parts, Utility::pid_t ppid)
326{
295c4a00 327 UeberBackend B;
6242d8a4 328 try {
e6a9dde5 329 g_log<<Logger::Error<<"Rediscovery was requested"<<endl;
6242d8a4 330 string status="Ok";
295c4a00 331 B.rediscover(&status);
6242d8a4
KM
332 return status;
333 }
334 catch(PDNSException &ae) {
335 return ae.reason;
336 }
337
12c86877
BH
338}
339
340string DLReloadHandler(const vector<string>&parts, Utility::pid_t ppid)
341{
295c4a00
CH
342 UeberBackend B;
343 B.reload();
e6a9dde5 344 g_log<<Logger::Error<<"Reload was requested"<<endl;
12c86877
BH
345 return "Ok";
346}
64bcb6be 347
f45a622c 348
ca8e1742 349string DLListZones(const vector<string>&parts, Utility::pid_t ppid)
767da1a0
RA
350{
351 UeberBackend B;
e6a9dde5 352 g_log<<Logger::Notice<<"Received request to list zones."<<endl;
767da1a0
RA
353 vector<DomainInfo> domains;
354 B.getAllDomains(&domains);
355 ostringstream ret;
356 int kindFilter = -1;
357 if (parts.size() > 1) {
358 if (toUpper(parts[1]) == "MASTER")
359 kindFilter = 0;
360 else if (toUpper(parts[1]) == "SLAVE")
361 kindFilter = 1;
362 else if (toUpper(parts[1]) == "NATIVE")
363 kindFilter = 2;
364 }
365
366 int count = 0;
367
cb167afd
CHB
368 for (const auto& di: domains) {
369 if (di.kind == kindFilter || kindFilter == -1) {
370 ret<<di.zone.toString()<<endl;
767da1a0
RA
371 count++;
372 }
373 }
374 if (kindFilter != -1)
36811022 375 ret<<parts[1]<<" zonecount:"<<count;
767da1a0 376 else
36811022 377 ret<<"All zonecount:"<<count;
767da1a0
RA
378
379 return ret.str();
380}
3e8216c8 381
24e0b305 382#ifdef HAVE_P11KIT1
248d701f 383extern bool PKCS11ModuleSlotLogin(const std::string& module, const string& tokenId, const std::string& pin);
24e0b305
AT
384#endif
385
386string DLTokenLogin(const vector<string>&parts, Utility::pid_t ppid)
387{
388#ifndef HAVE_P11KIT1
389 return "PKCS#11 support not compiled in";
390#else
391 if (parts.size() != 4) {
335da0ba 392 return "invalid number of parameters, needs 4, got " + std::to_string(parts.size());
24e0b305
AT
393 }
394
248d701f 395 if (PKCS11ModuleSlotLogin(parts[1], parts[2], parts[3])) {
24e0b305
AT
396 return "logged in";
397 } else {
398 return "could not log in, check logs";
399 }
400#endif
401}