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