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