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