• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 9404151942

06 Jun 2024 04:02PM UTC coverage: 62.315% (-2.3%) from 64.59%
9404151942

push

github

web-flow
Merge pull request #14300 from omoerbeek/rec-doc-max-map-count

rec: document vm.max_map_count can be too low

35536 of 88168 branches covered (40.3%)

Branch coverage included in aggregate %.

120183 of 161724 relevant lines covered (74.31%)

2983853.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

12.11
/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 <csignal>
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 "auth-main.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
{
×
94
  try {
×
95
    extern StatBag S;
×
96
    string ret("Wrong number of parameters");
×
97
    if (parts.size() == 2) {
×
98
      if (parts[1] == "*")
×
99
        ret = S.directory();
×
100
      else if (parts[1].length() && parts[1][parts[1].length() - 1 ] == '*')
×
101
        ret = S.directory(parts[1].substr(0, parts[1].length() - 1));
×
102
      else
×
103
        ret = S.getValueStr(parts[1]);
×
104
    }
×
105

106
    return ret;
×
107
  }
×
108
  catch (...) {
×
109
    return "Unknown";
×
110
  }
×
111
}
×
112

113
void setStatus(const string &str)
114
{
×
115
  d_status=str;
×
116
}
×
117

118
string DLStatusHandler(const vector<string>& /* parts */, Utility::pid_t ppid)
119
{
×
120
  ostringstream os;
×
121
  os<<ppid<<": "<<d_status;
×
122
  return os.str();
×
123
}
×
124

125
string DLUptimeHandler(const vector<string>& /* parts */, Utility::pid_t /* ppid */)
126
{
×
127
  ostringstream os;
×
128
  os<<humanDuration(time(nullptr)-g_starttime);
×
129
  return os.str();
×
130
}
×
131

132
string DLPurgeHandler(const vector<string>& parts, Utility::pid_t /* ppid */)
133
{
6✔
134
  ostringstream os;
6✔
135
  int ret=0;
6✔
136

137
  if(parts.size()>1) {
6!
138
    for (vector<string>::const_iterator i=++parts.begin();i<parts.end();++i) {
12✔
139
      g_log<<Logger::Warning<<"Cache clear request for '"<<*i<<"' received from operator"<<endl;
6✔
140
      ret+=purgeAuthCaches(*i);
6✔
141
      if(!boost::ends_with(*i, "$"))
6!
142
        DNSSECKeeper::clearCaches(DNSName(*i));
6✔
143
      else
×
144
        DNSSECKeeper::clearAllCaches(); // at least we do what we promise.. and a bit more!
×
145
    }
6✔
146
  }
6✔
147
  else {
×
148
    g_log<<Logger::Warning<<"Cache clear request received from operator"<<endl;
×
149
    ret = purgeAuthCaches();
×
150
    DNSSECKeeper::clearAllCaches();
×
151
  }
×
152

153
  os<<ret;
6✔
154
  return os.str();
6✔
155
}
6✔
156

157
string DLCCHandler(const vector<string>& /* parts */, Utility::pid_t /* ppid */)
158
{
×
159
  extern AuthPacketCache PC;
×
160
  extern AuthQueryCache QC;
×
161
  map<char,uint64_t> counts=QC.getCounts();
×
162
  uint64_t packetEntries = PC.size();
×
163
  ostringstream os;
×
164
  bool first=true;
×
165
  for(map<char,uint64_t>::const_iterator i=counts.begin();i!=counts.end();++i) {
×
166
    if(!first)
×
167
      os<<", ";
×
168
    first=false;
×
169

170
    if(i->first=='!')
×
171
      os<<"negative queries: ";
×
172
    else if(i->first=='Q')
×
173
      os<<"queries: ";
×
174
    else
×
175
      os<<"unknown: ";
×
176

177
    os<<i->second;
×
178
  }
×
179
  if(!first)
×
180
    os<<", ";
×
181
  os<<"packets: "<<packetEntries;
×
182

183
  return os.str();
×
184
}
×
185

186
string DLQTypesHandler(const vector<string>& /* parts */, Utility::pid_t /* ppid */)
187
{
×
188
  return g_rs.getQTypeReport();
×
189
}
×
190

191
string DLRSizesHandler(const vector<string>& /* parts */, Utility::pid_t /* ppid */)
192
{
×
193
  typedef map<uint16_t, uint64_t> respsizes_t;
×
194
  respsizes_t respsizes = g_rs.getSizeResponseCounts();
×
195
  ostringstream os;
×
196
  boost::format fmt("%d\t%d\n");
×
197
  for(const respsizes_t::value_type& val :  respsizes) {
×
198
    os << (fmt % val.first % val.second).str();
×
199
  }
×
200
  return os.str();
×
201
}
×
202

203
string DLRemotesHandler(const vector<string>& /* parts */, Utility::pid_t /* ppid */)
204
{
×
205
  extern StatBag S;
×
206
  typedef vector<pair<string, unsigned int> > totals_t;
×
207
  totals_t totals = S.getRing("remotes");
×
208
  string ret;
×
209
  boost::format fmt("%s\t%d\n");
×
210
  for(totals_t::value_type& val :  totals) {
×
211
    ret += (fmt % val.first % val.second).str();
×
212
  }
×
213
  return ret;
×
214
}
×
215

216
string DLSettingsHandler(const vector<string>& parts, Utility::pid_t /* ppid */)
217
{
×
218
  static const char *whitelist[]={"query-logging",nullptr};
×
219
  const char **p;
×
220

221
  if(parts.size()!=3) {
×
222
    return "Syntax: set variable value";
×
223
  }
×
224

225
  for(p=whitelist;*p;p++)
×
226
    if(*p==parts[1])
×
227
      break;
×
228
  if(*p) {
×
229
    ::arg().set(parts[1])=parts[2];
×
230
    g_log<<Logger::Warning<<"Configuration change for setting '"<<parts[1]<<"' to value '"<<parts[2]<<"' received from operator"<<endl;
×
231
    return "done";
×
232
  }
×
233
  else
×
234
    return "This setting cannot be changed at runtime, or no such setting";
×
235

236
}
×
237

238
string DLVersionHandler(const vector<string>& /* parts */, Utility::pid_t /* ppid */)
239
{
×
240
  return VERSION;
×
241
}
×
242

243
string DLNotifyRetrieveHandler(const vector<string>& parts, Utility::pid_t /* ppid */)
244
{
16✔
245
  extern CommunicatorClass Communicator;
16✔
246
  ostringstream os;
16✔
247
  if(parts.size()!=2 && parts.size()!=3)
16!
248
    return "syntax: retrieve zone [ip]";
×
249

250
  DNSName domain;
16✔
251
  try {
16✔
252
    domain = DNSName(parts[1]);
16✔
253
  } catch (...) {
16✔
254
    return "Failed to parse zone as valid DNS name";
×
255
  }
×
256

257
  ComboAddress primary_ip;
16✔
258
  bool override_primary = false;
16✔
259
  if (parts.size() == 3) {
16!
260
    try {
×
261
      primary_ip = ComboAddress{parts[2], 53};
×
262
    } catch (...) {
×
263
      return "Invalid primary address";
×
264
    }
×
265
    override_primary = true;
×
266
  }
×
267

268
  DomainInfo di;
16✔
269
  UeberBackend B;
16✔
270
  if(!B.getDomainInfo(domain, di)) {
16✔
271
    return " Zone '" + domain.toString() + "' unknown";
8✔
272
  }
8✔
273

274
  if (override_primary) {
8!
275
    di.primaries.clear();
×
276
    di.primaries.push_back(primary_ip);
×
277
  }
×
278

279
  if (!override_primary && (!di.isSecondaryType() || di.primaries.empty()))
8!
280
    return "Zone '" + domain.toString() + "' is not a secondary/consumer zone (or has no primary defined)";
×
281

282
  shuffle(di.primaries.begin(), di.primaries.end(), pdns::dns_random_engine());
8✔
283
  const auto& primary = di.primaries.front();
8✔
284
  Communicator.addSuckRequest(domain, primary, SuckRequest::PdnsControl, override_primary);
8✔
285
  g_log << Logger::Warning << "Retrieval request for zone '" << domain << "' from primary '" << primary << "' received from operator" << endl;
8✔
286
  return "Added retrieval request for '" + domain.toLogString() + "' from primary " + primary.toLogString();
8✔
287
}
8✔
288

289
string DLNotifyHostHandler(const vector<string>& parts, Utility::pid_t /* ppid */)
290
{
×
291
  extern CommunicatorClass Communicator;
×
292
  ostringstream os;
×
293
  if(parts.size()!=3)
×
294
    return "syntax: notify-host zone ip";
×
295
  if(!::arg().mustDo("primary") && !(::arg().mustDo("secondary") && ::arg().mustDo("secondary-do-renotify")))
×
296
    return "PowerDNS not configured as primary, or secondary with re-notifications";
×
297

298
  DNSName domain;
×
299
  try {
×
300
    domain = DNSName(parts[1]);
×
301
  } catch (...) {
×
302
    return "Failed to parse zone as valid DNS name";
×
303
  }
×
304

305
  try {
×
306
    ComboAddress ca(parts[2]);
×
307
  } catch(...)
×
308
  {
×
309
    return "Unable to convert '"+parts[2]+"' to an IP address";
×
310
  }
×
311

312
  g_log << Logger::Warning << "Notification request to host " << parts[2] << " for zone '" << domain << "' received from operator" << endl;
×
313
  Communicator.notify(domain, parts[2]);
×
314
  return "Added to queue";
×
315
}
×
316

317
string DLNotifyHandler(const vector<string>& parts, Utility::pid_t /* ppid */)
318
{
×
319
  extern CommunicatorClass Communicator;
×
320
  UeberBackend B;
×
321
  if(parts.size()!=2)
×
322
    return "syntax: notify zone";
×
323
  if(!::arg().mustDo("primary") && !(::arg().mustDo("secondary") && ::arg().mustDo("secondary-do-renotify")))
×
324
    return "PowerDNS not configured as primary (primary), or secondary (secondary) with re-notifications";
×
325
  g_log << Logger::Warning << "Notification request for zone '" << parts[1] << "' received from operator" << endl;
×
326

327
  if (parts[1] == "*") {
×
328
    vector<DomainInfo> domains;
×
329
    B.getAllDomains(&domains, true, false);
×
330

331
    int total = 0;
×
332
    int notified = 0;
×
333
    for (const auto& di : domains) {
×
334
      if (di.kind != DomainInfo::Native) { // Primary and secondary if secondary-do-renotify is enabled
×
335
        total++;
×
336
        if(Communicator.notifyDomain(di.zone, &B))
×
337
          notified++;
×
338
      }
×
339
    }
×
340

341
    if (total != notified)
×
342
      return std::to_string(notified)+" out of "+std::to_string(total)+" zones added to queue - see log";
×
343
    return "Added " + std::to_string(total) + " MASTER/SLAVE/PRODUCER/CONSUMER zones to queue";
×
344
  } else {
×
345
    DNSName domain;
×
346
    try {
×
347
      domain = DNSName(parts[1]);
×
348
    } catch (...) {
×
349
      return "Failed to parse zone as valid DNS name";
×
350
    }
×
351
    if(!Communicator.notifyDomain(DNSName(parts[1]), &B))
×
352
      return "Failed to add to the queue - see log";
×
353
    return "Added to queue";
×
354
  }
×
355
}
×
356

357
string DLRediscoverHandler(const vector<string>& /* parts */, Utility::pid_t /* ppid */)
358
{
×
359
  UeberBackend B;
×
360
  try {
×
361
    g_log<<Logger::Error<<"Rediscovery was requested"<<endl;
×
362
    string status="Ok";
×
363
    B.rediscover(&status);
×
364
    return status;
×
365
  }
×
366
  catch(PDNSException &ae) {
×
367
    return ae.reason;
×
368
  }
×
369

370
}
×
371

372
string DLReloadHandler(const vector<string>& /* parts */, Utility::pid_t /* ppid */)
373
{
×
374
  UeberBackend B;
×
375
  B.reload();
×
376
  g_log<<Logger::Error<<"Reload was requested"<<endl;
×
377
  return "Ok";
×
378
}
×
379

380
string DLListZones(const vector<string>& parts, Utility::pid_t /* ppid */)
381
{
×
382
  UeberBackend B;
×
383
  g_log<<Logger::Notice<<"Received request to list zones."<<endl;
×
384
  vector<DomainInfo> domains;
×
385
  B.getAllDomains(&domains, false, false);
×
386
  ostringstream ret;
×
387
  DomainInfo::DomainKind kind;
×
388
  if (parts.size() > 1) {
×
389
    kind = DomainInfo::stringToKind(parts.at(1));
×
390
  }
×
391
  else {
×
392
    kind = DomainInfo::All;
×
393
  }
×
394

395
  int count = 0;
×
396

397
  for (const auto& di: domains) {
×
398
    if (di.kind == kind || kind == DomainInfo::All) {
×
399
      ret<<di.zone.toString()<<endl;
×
400
      count++;
×
401
    }
×
402
  }
×
403

404
  ret << DomainInfo::getKindString(kind) << " zonecount: " << count;
×
405

406
  return ret.str();
×
407
}
×
408

409
#ifdef HAVE_P11KIT1
410
extern bool PKCS11ModuleSlotLogin(const std::string& module, const string& tokenId, const std::string& pin);
411
#endif
412

413
string DLTokenLogin([[maybe_unused]] const vector<string>& parts, [[maybe_unused]] Utility::pid_t /* ppid */)
414
{
×
415
#ifndef HAVE_P11KIT1
416
  return "PKCS#11 support not compiled in";
417
#else
418
  if (parts.size() != 4) {
×
419
    return "invalid number of parameters, needs 4, got " + std::to_string(parts.size());
×
420
  }
×
421

422
  if (PKCS11ModuleSlotLogin(parts[1], parts[2], parts[3])) {
×
423
    return "logged in";
×
424
  } else {
×
425
    return "could not log in, check logs";
×
426
  }
×
427
#endif
×
428
}
×
429

430
string DLSuckRequests(const vector<string>& /* parts */, Utility::pid_t /* ppid */)
431
{
×
432
  string ret;
×
433
  for (auto const &d: Communicator.getSuckRequests()) {
×
434
    ret += d.first.toString() + " " + d.second.toString() + "\n";
×
435
  }
×
436
  return ret;
×
437
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc