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

PowerDNS / pdns / 11393698597

17 Oct 2024 12:03PM UTC coverage: 61.73% (-2.9%) from 64.617%
11393698597

push

github

web-flow
Merge pull request #14778 from fredmorcos/lmdb-safe-cleanups

Some cleanups for lmdb-safe

51822 of 131368 branches covered (39.45%)

Branch coverage included in aggregate %.

100 of 119 new or added lines in 4 files covered. (84.03%)

10322 existing lines in 127 files now uncovered.

140614 of 180372 relevant lines covered (77.96%)

5141811.86 hits per line

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

60.17
/modules/lua2backend/lua2api2.hh
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
 * MERCHANTAPILITY 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
#pragma once
23
#include "boost/lexical_cast.hpp"
24
#include "boost/algorithm/string/join.hpp"
25
#include "pdns/arguments.hh"
26

27
#include "pdns/dnsbackend.hh"
28
#include "pdns/lua-auth4.hh"
29

30
class Lua2BackendAPIv2 : public DNSBackend, AuthLua4
31
{
32
private:
33
  typedef std::function<void()> init_call_t;
34
  typedef std::function<void()> deinit_call_t;
35

36
  typedef std::vector<std::pair<string, string>> lookup_context_t;
37

38
  typedef std::vector<std::pair<int, std::vector<std::pair<string, boost::variant<bool, int, DNSName, string, QType>>>>> lookup_result_t;
39
  typedef std::function<lookup_result_t(const QType& qtype, const DNSName& qname, int domain_id, const lookup_context_t& ctx)> lookup_call_t;
40

41
  typedef boost::variant<bool, lookup_result_t> list_result_t;
42
  typedef std::function<list_result_t(const DNSName& qname, int domain_id)> list_call_t;
43

44
  typedef vector<pair<string, boost::variant<bool, long, string, vector<string>>>> domaininfo_result_t;
45
  typedef boost::variant<bool, domaininfo_result_t> get_domaininfo_result_t;
46
  typedef vector<pair<DNSName, domaininfo_result_t>> get_all_domains_result_t;
47
  typedef std::function<get_domaininfo_result_t(const DNSName& domain)> get_domaininfo_call_t;
48
  typedef std::function<get_all_domains_result_t()> get_all_domains_call_t;
49

50
  typedef vector<pair<int, string>> domain_metadata_result_t;
51
  typedef boost::variant<bool, domain_metadata_result_t> get_domain_metadata_result_t;
52
  typedef boost::variant<bool, vector<pair<string, domain_metadata_result_t>>> get_all_domain_metadata_result_t;
53
  typedef std::function<get_domain_metadata_result_t(const DNSName& domain, const string& kind)> get_domain_metadata_call_t;
54
  typedef std::function<get_all_domain_metadata_result_t(const DNSName& domain)> get_all_domain_metadata_call_t;
55

56
  typedef vector<pair<string, boost::variant<bool, int, string>>> keydata_result_t;
57
  typedef boost::variant<bool, vector<pair<int, keydata_result_t>>> get_domain_keys_result_t;
58
  typedef std::function<get_domain_keys_result_t(const DNSName& domain)> get_domain_keys_call_t;
59

60
  typedef std::vector<std::pair<string, boost::variant<string, DNSName>>> before_and_after_names_result_t;
61
  typedef boost::variant<bool, before_and_after_names_result_t> get_before_and_after_names_absolute_result_t;
62
  typedef std::function<get_before_and_after_names_absolute_result_t(int id, const DNSName& qname)> get_before_and_after_names_absolute_call_t;
63

64
  typedef std::function<void(int, long)> set_notified_call_t;
65

66
  typedef std::function<string(const string& cmd)> direct_backend_cmd_call_t;
67

21✔
68
public:
21✔
69
  Lua2BackendAPIv2(const string& suffix)
21✔
70
  {
21✔
71
    d_include_path = ::arg()["lua-global-include-dir"];
21✔
72
    setArgPrefix("lua2" + suffix);
21✔
73
    d_debug_log = mustDo("query-logging");
74
    prepareContext();
75
    loadFile(getArg("filename"));
76
  }
77

48✔
78
  ~Lua2BackendAPIv2() override;
48✔
79

80
#define logCall(func, var)                                                                               \
81
  {                                                                                                      \
48✔
82
    if (d_debug_log) {                                                                                   \
83
      g_log << Logger::Debug << "[" << getPrefix() << "] Calling " << func << "(" << var << ")" << endl; \
128✔
84
    }                                                                                                    \
128✔
UNCOV
85
  }
×
86
#define logResult(var)                                                \
UNCOV
87
  {                                                                   \
×
88
    if (d_debug_log) {                                                \
128✔
89
      g_log << Logger::Debug << "[" << getPrefix() << "] Got result " \
90
            << "'" << var << "'" << endl;                             \
91
    }                                                                 \
21✔
92
  }
21✔
93

21✔
94
  void postPrepareContext() override
95
  {
96
    AuthLua4::postPrepareContext();
21✔
97
  }
21✔
98

21✔
99
  void postLoad() override
21✔
100
  {
21✔
101
    f_lookup = d_lw->readVariable<boost::optional<lookup_call_t>>("dns_lookup").get_value_or(0);
21✔
102
    f_list = d_lw->readVariable<boost::optional<list_call_t>>("dns_list").get_value_or(0);
21✔
103
    f_get_all_domains = d_lw->readVariable<boost::optional<get_all_domains_call_t>>("dns_get_all_domains").get_value_or(0);
21✔
104
    f_get_domaininfo = d_lw->readVariable<boost::optional<get_domaininfo_call_t>>("dns_get_domaininfo").get_value_or(0);
21✔
105
    f_get_domain_metadata = d_lw->readVariable<boost::optional<get_domain_metadata_call_t>>("dns_get_domain_metadata").get_value_or(0);
21✔
106
    f_get_all_domain_metadata = d_lw->readVariable<boost::optional<get_all_domain_metadata_call_t>>("dns_get_all_domain_metadata").get_value_or(0);
107
    f_get_domain_keys = d_lw->readVariable<boost::optional<get_domain_keys_call_t>>("dns_get_domain_keys").get_value_or(0);
21✔
108
    f_get_before_and_after_names_absolute = d_lw->readVariable<boost::optional<get_before_and_after_names_absolute_call_t>>("dns_get_before_and_after_names_absolute").get_value_or(0);
21!
UNCOV
109
    f_set_notified = d_lw->readVariable<boost::optional<set_notified_call_t>>("dns_set_notified").get_value_or(0);
×
110

111
    auto init = d_lw->readVariable<boost::optional<init_call_t>>("dns_init").get_value_or(0);
21✔
112
    if (init)
21!
113
      init();
21!
114

115
    f_deinit = d_lw->readVariable<boost::optional<deinit_call_t>>("dns_deinit").get_value_or(0);
116

117
    if (f_lookup == nullptr)
21!
118
      throw PDNSException("dns_lookup missing");
21✔
119

15!
120
    /* see if dnssec support is wanted */
121
    d_dnssec = d_lw->readVariable<boost::optional<bool>>("dns_dnssec").get_value_or(false);
15!
UNCOV
122
    if (d_dnssec) {
✔
123
      if (f_get_domain_metadata == nullptr)
15!
124
        throw PDNSException("dns_dnssec is true but dns_get_domain_metadata is missing");
15!
UNCOV
125
      if (f_get_before_and_after_names_absolute == nullptr)
×
126
        throw PDNSException("dns_dnssec is true but dns_get_before_and_after_names_absolute is missing");
15✔
127
      /* domain keys is not strictly speaking necessary for dnssec backend */
21✔
128
      if (f_get_domain_keys == nullptr)
15!
129
        g_log << Logger::Warning << "dns_get_domain_keys missing - cannot do live signing" << endl;
UNCOV
130
    }
×
UNCOV
131
  }
×
132

133
  bool doesDNSSEC() override
134
  {
135
    return d_dnssec;
29✔
136
  }
103✔
137

103✔
138
  void parseLookup(const lookup_result_t& result)
437✔
139
  {
437✔
140
    for (const auto& row : result) {
103✔
UNCOV
141
      DNSResourceRecord rec;
×
142
      for (const auto& item : row.second) {
103✔
UNCOV
143
        if (item.first == "type") {
✔
144
          if (item.second.which() == 1)
103✔
145
            rec.qtype = QType(boost::get<int>(item.second));
103✔
UNCOV
146
          else if (item.second.which() == 3)
×
147
            rec.qtype = boost::get<string>(item.second);
×
148
          else if (item.second.which() == 4)
103!
149
            rec.qtype = boost::get<QType>(item.second);
334✔
150
          else
103!
151
            throw PDNSException("Unsupported value for type");
×
152
        }
103!
153
        else if (item.first == "name") {
103✔
UNCOV
154
          if (item.second.which() == 3)
×
155
            rec.qname = DNSName(boost::get<string>(item.second));
×
156
          else if (item.second.which() == 2)
103!
157
            rec.qname = boost::get<DNSName>(item.second);
231✔
158
          else
25✔
159
            throw PDNSException("Unsupported value for name");
206!
UNCOV
160
        }
×
161
        else if (item.first == "domain_id")
206✔
UNCOV
162
          rec.domain_id = boost::get<int>(item.second);
×
163
        else if (item.first == "auth")
206✔
164
          rec.auth = boost::get<bool>(item.second);
103✔
165
        else if (item.first == "last_modified")
103✔
166
          rec.last_modified = static_cast<time_t>(boost::get<int>(item.second));
103✔
UNCOV
167
        else if (item.first == "ttl")
✔
UNCOV
168
          rec.ttl = boost::get<int>(item.second);
×
UNCOV
169
        else if (item.first == "content")
×
UNCOV
170
          rec.setContent(boost::get<string>(item.second));
×
171
        else if (item.first == "scopeMask")
437!
172
          rec.scopeMask = boost::get<int>(item.second);
103!
173
        else
103✔
174
          g_log << Logger::Warning << "Unsupported key '" << item.first << "' in lookup or list result" << endl;
103✔
175
      }
29!
UNCOV
176
      logResult(rec.qname << " IN " << rec.qtype.toString() << " " << rec.ttl << " " << rec.getZoneRepresentation());
×
177
      d_result.push_back(rec);
29✔
178
    }
179
    if (d_result.empty() && d_debug_log)
33!
180
      g_log << Logger::Debug << "[" << getPrefix() << "] Got empty result" << endl;
6✔
181
  }
6!
182

183
  bool list(const DNSName& target, int domain_id, bool /* include_disabled */ = false) override
UNCOV
184
  {
×
185
    if (f_list == nullptr) {
6!
186
      g_log << Logger::Error << "[" << getPrefix() << "] dns_list missing - cannot do AXFR" << endl;
6!
187
      return false;
×
188
    }
189

6!
190
    if (d_result.size() != 0)
6!
191
      throw PDNSException("list attempted while another was running");
192

6!
UNCOV
193
    logCall("list", "target=" << target << ",domain_id=" << domain_id);
×
194
    list_result_t result = f_list(target, domain_id);
195

6✔
196
    if (result.which() == 0)
6!
197
      return false;
6✔
198

6✔
199
    parseLookup(boost::get<lookup_result_t>(result));
200

201
    return true;
23✔
202
  }
23!
203

204
  void lookup(const QType& qtype, const DNSName& qname, int domain_id, DNSPacket* p = nullptr) override
205
  {
23✔
206
    if (d_result.size() != 0)
23✔
207
      throw PDNSException("lookup attempted while another was running");
5✔
208

5✔
209
    lookup_context_t ctx;
5✔
210
    if (p != NULL) {
23✔
211
      ctx.emplace_back(lookup_context_t::value_type{"source_address", p->getInnerRemote().toString()});
23!
212
      ctx.emplace_back(lookup_context_t::value_type{"real_source_address", p->getRealRemote().toString()});
23✔
213
    }
23✔
214

23✔
215
    logCall("lookup", "qtype=" << qtype.toString() << ",qname=" << qname << ",domain_id=" << domain_id);
23!
216
    lookup_result_t result = f_lookup(qtype, qname, domain_id, ctx);
217
    parseLookup(result);
132✔
218
  }
132✔
219

29✔
220
  bool get(DNSResourceRecord& rr) override
103✔
221
  {
103✔
222
    if (d_result.size() == 0)
103✔
223
      return false;
132✔
224
    rr = std::move(d_result.front());
225
    d_result.pop_front();
UNCOV
226
    return true;
×
UNCOV
227
  }
×
228

229
  string directBackendCmd(const string& querystr) override
230
  {
×
231
    string::size_type pos = querystr.find_first_of(" \t");
×
232
    string cmd = querystr;
×
233
    string par = "";
×
234
    if (pos != string::npos) {
×
235
      cmd = querystr.substr(0, pos);
×
236
      par = querystr.substr(pos + 1);
×
237
    }
×
238
    direct_backend_cmd_call_t f = d_lw->readVariable<boost::optional<direct_backend_cmd_call_t>>(cmd).get_value_or(0);
×
239
    if (f == nullptr) {
×
240
      return cmd + "not found";
×
241
    }
242
    logCall(cmd, "parameter=" << par);
×
243
    return f(par);
×
244
  }
×
245

246
  void setNotified(uint32_t id, uint32_t serial) override
×
247
  {
×
248
    if (f_set_notified == NULL)
×
249
      return;
250
    logCall("dns_set_notified", "id=" << static_cast<int>(id) << ",serial=" << serial);
×
251
    f_set_notified(static_cast<int>(id), serial);
5✔
252
  }
10✔
253

10!
254
  void parseDomainInfo(const domaininfo_result_t& row, DomainInfo& di)
255
  {
10!
UNCOV
256
    for (const auto& item : row) {
✔
257
      if (item.first == "account")
10!
258
        di.account = boost::get<string>(item.second);
×
UNCOV
259
      else if (item.first == "last_check")
×
260
        di.last_check = static_cast<time_t>(boost::get<long>(item.second));
10✔
261
      else if (item.first == "masters")
5!
262
        for (const auto& primary : boost::get<vector<string>>(item.second))
5!
263
          di.primaries.push_back(ComboAddress(primary, 53));
×
264
      else if (item.first == "id")
5✔
265
        di.id = static_cast<int>(boost::get<long>(item.second));
5✔
UNCOV
266
      else if (item.first == "notified_serial")
×
267
        di.notified_serial = static_cast<unsigned int>(boost::get<long>(item.second));
×
UNCOV
268
      else if (item.first == "serial")
×
UNCOV
269
        di.serial = static_cast<unsigned int>(boost::get<long>(item.second));
×
270
      else if (item.first == "kind")
10!
271
        di.kind = DomainInfo::stringToKind(boost::get<string>(item.second));
5✔
272
      else
5!
273
        g_log << Logger::Warning << "Unsupported key '" << item.first << "' in domaininfo result" << endl;
5✔
274
    }
275
    di.backend = this;
276
    logResult("zone=" << di.zone << ",serial=" << di.serial << ",kind=" << di.getKindString());
6!
277
  }
6✔
278

279
  bool getDomainInfo(const DNSName& domain, DomainInfo& di, bool /* getSerial */ = true) override
3✔
280
  {
3!
UNCOV
281
    if (f_get_domaininfo == nullptr) {
✔
282
      // use getAuth instead
283
      SOAData sd;
3✔
284
      if (!getAuth(domain, &sd))
3!
285
        return false;
3✔
286

3✔
287
      di.zone = domain;
3✔
288
      di.backend = this;
289
      di.serial = sd.serial;
3!
290
      return true;
3✔
291
    }
292

3!
UNCOV
293
    logCall("get_domaininfo", "domain=" << domain);
×
294
    get_domaininfo_result_t result = f_get_domaininfo(domain);
295

3✔
296
    if (result.which() == 0)
3!
297
      return false;
298

3✔
299
    di.zone = domain;
3✔
300
    parseDomainInfo(boost::get<domaininfo_result_t>(result), di);
301

302
    return true;
1✔
303
  }
1!
304

305
  void getAllDomains(vector<DomainInfo>* domains, bool /* getSerial */, bool /* include_disabled */) override
306
  {
1!
307
    if (f_get_all_domains == nullptr)
2✔
308
      return;
2✔
309

2✔
310
    logCall("get_all_domains", "");
2!
311
    for (const auto& row : f_get_all_domains()) {
2✔
312
      DomainInfo di;
2✔
313
      di.zone = row.first;
2✔
314
      logResult(di.zone);
1!
315
      parseDomainInfo(row.second, di);
316
      domains->push_back(di);
317
    }
6✔
318
  }
6!
319

6✔
320
  bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string>>& meta) override
UNCOV
321
  {
×
UNCOV
322
    if (f_get_all_domain_metadata == nullptr)
×
UNCOV
323
      return false;
×
324

325
    logCall("get_all_domain_metadata", "name=" << name);
×
326
    get_all_domain_metadata_result_t result = f_get_all_domain_metadata(name);
×
327
    if (result.which() == 0)
×
328
      return false;
×
329

330
    for (const auto& row : boost::get<vector<pair<string, domain_metadata_result_t>>>(result)) {
×
331
      meta[row.first].clear();
×
332
      for (const auto& item : row.second)
×
333
        meta[row.first].push_back(item.second);
×
334
      logResult("kind=" << row.first << ",value=" << boost::algorithm::join(meta[row.first], ", "));
×
335
    }
336

337
    return true;
×
338
  }
×
339

340
  bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) override
341
  {
×
342
    if (f_get_domain_metadata == nullptr)
×
343
      return false;
×
344

345
    logCall("get_domain_metadata", "name=" << name << ",kind=" << kind);
×
346
    get_domain_metadata_result_t result = f_get_domain_metadata(name, kind);
×
347
    if (result.which() == 0)
×
348
      return false;
×
349

350
    meta.clear();
×
351
    for (const auto& item : boost::get<domain_metadata_result_t>(result))
×
352
      meta.push_back(item.second);
×
353

354
    logResult("value=" << boost::algorithm::join(meta, ", "));
×
355
    return true;
6✔
356
  }
6✔
357

3✔
358
  bool getDomainKeys(const DNSName& name, std::vector<DNSBackend::KeyData>& keys) override
359
  {
3!
360
    if (f_get_domain_keys == nullptr)
3✔
361
      return false;
362

3!
UNCOV
363
    logCall("get_domain_keys", "name=" << name);
×
364
    get_domain_keys_result_t result = f_get_domain_keys(name);
365

6✔
366
    if (result.which() == 0)
6!
367
      return false;
6✔
368

24✔
369
    for (const auto& row : boost::get<vector<pair<int, keydata_result_t>>>(result)) {
24✔
370
      DNSBackend::KeyData key;
6✔
371
      key.published = true;
18✔
372
      for (const auto& item : row.second) {
6✔
373
        if (item.first == "content")
12✔
374
          key.content = boost::get<string>(item.second);
6✔
375
        else if (item.first == "id")
6✔
376
          key.id = static_cast<unsigned int>(boost::get<int>(item.second));
6✔
UNCOV
377
        else if (item.first == "flags")
✔
UNCOV
378
          key.flags = static_cast<unsigned int>(boost::get<int>(item.second));
×
UNCOV
379
        else if (item.first == "active")
×
UNCOV
380
          key.active = boost::get<bool>(item.second);
×
381
        else if (item.first == "published")
24!
382
          key.published = boost::get<bool>(item.second);
6!
383
        else
6✔
384
          g_log << Logger::Warning << "[" << getPrefix() << "] Unsupported key '" << item.first << "' in keydata result" << endl;
6✔
385
      }
386
      logResult("id=" << key.id << ",flags=" << key.flags << ",active=" << (key.active ? "true" : "false") << ",published=" << (key.published ? "true" : "false"));
3!
387
      keys.push_back(key);
3✔
388
    }
389

390
    return true;
12✔
391
  }
12!
392

393
  bool getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after) override
394
  {
12!
395
    if (f_get_before_and_after_names_absolute == nullptr)
12!
396
      return false;
397

12!
UNCOV
398
    logCall("get_before_and_after_names_absolute", "id=<<" << id << ",qname=" << qname);
×
399
    get_before_and_after_names_absolute_result_t result = f_get_before_and_after_names_absolute(id, qname);
400

12✔
401
    if (result.which() == 0)
12!
402
      return false;
×
403

UNCOV
404
    before_and_after_names_result_t row = boost::get<before_and_after_names_result_t>(result);
×
405
    if (row.size() != 3) {
36✔
406
      g_log << Logger::Error << "Invalid result from dns_get_before_and_after_names_absolute, expected array with 3 items, got " << row.size() << "item(s)" << endl;
36✔
407
      return false;
36!
408
    }
×
409
    for (const auto& item : row) {
36✔
410
      DNSName value;
36✔
411
      if (item.second.which() == 0)
36✔
412
        value = DNSName(boost::get<string>(item.second));
12✔
413
      else
24✔
414
        value = DNSName(boost::get<DNSName>(item.second));
12✔
415
      if (item.first == "unhashed")
12✔
416
        unhashed = value;
12✔
UNCOV
417
      else if (item.first == "before")
✔
UNCOV
418
        before = value;
×
UNCOV
419
      else if (item.first == "after")
×
UNCOV
420
        after = value;
×
421
      else {
36✔
422
        g_log << Logger::Error << "Invalid result from dns_get_before_and_after_names_absolute, unexpected key " << item.first << endl;
423
        return false;
12!
424
      }
12✔
425
    }
12✔
426

427
    logResult("unhashed=" << unhashed << ",before=" << before << ",after=" << after);
12!
428
    return true;
429
  }
430

431
private:
432
  std::list<DNSResourceRecord> d_result;
433
  bool d_debug_log{false};
434
  bool d_dnssec{false};
435

436
  lookup_call_t f_lookup;
437
  list_call_t f_list;
438

439
  get_domaininfo_call_t f_get_domaininfo;
440
  get_all_domains_call_t f_get_all_domains;
441

442
  get_domain_metadata_call_t f_get_domain_metadata;
443
  get_all_domain_metadata_call_t f_get_all_domain_metadata;
444

445
  get_domain_keys_call_t f_get_domain_keys;
446

447
  get_before_and_after_names_absolute_call_t f_get_before_and_after_names_absolute;
448

449
  set_notified_call_t f_set_notified;
450

451
  deinit_call_t f_deinit;
452
};
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

© 2025 Coveralls, Inc