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