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

PowerDNS / pdns / 30049382396

23 Jul 2026 11:59AM UTC coverage: 32.397% (-38.8%) from 71.153%
30049382396

push

github

web-flow
Merge pull request #17762 from omoerbeek/rec-wildcard-cname-proof-validation-bypass

rec: Wildcard CNAME proof validation bypass

7712 of 42538 branches covered (18.13%)

Branch coverage included in aggregate %.

21340 of 47137 relevant lines covered (45.27%)

1355193.37 hits per line

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

0.0
/modules/lua2backend/lua2api2.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
 * 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
#ifdef HAVE_CONFIG_H
23
#include "config.h"
24
#endif
25
#include "lua2backend.hh"
26

27
Lua2BackendAPIv2::Lua2BackendAPIv2(Logr::log_t slog, const string& suffix)
28
{
×
29
  d_slog = slog;
×
30
  d_include_path = ::arg()["lua-global-include-dir"];
×
31
  setArgPrefix("lua2" + suffix);
×
32
  d_debug_log = mustDo("query-logging");
33
  prepareContext();
34
  loadFile(getArg("filename"));
35
}
36

37
Lua2BackendAPIv2::~Lua2BackendAPIv2()
38
{
39
  if (f_deinit) {
40
    f_deinit();
41
  }
42
}
43

44
void Lua2BackendAPIv2::postPrepareContext()
45
{
46
  AuthLua4::postPrepareContext();
47
}
48

49
void Lua2BackendAPIv2::postLoad()
50
{
51
  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks): clang-tidy is adamant readVariable may leak a std::function in LuaContext::Reader(), but only warns for the first readVariable call.
52
  f_lookup = d_lw->readVariable<boost::optional<lookup_call_t>>("dns_lookup").get_value_or(nullptr);
53
  f_list = d_lw->readVariable<boost::optional<list_call_t>>("dns_list").get_value_or(nullptr);
54
  f_get_all_domains = d_lw->readVariable<boost::optional<get_all_domains_call_t>>("dns_get_all_domains").get_value_or(nullptr);
55
  f_get_domaininfo = d_lw->readVariable<boost::optional<get_domaininfo_call_t>>("dns_get_domaininfo").get_value_or(nullptr);
56
  f_get_domain_metadata = d_lw->readVariable<boost::optional<get_domain_metadata_call_t>>("dns_get_domain_metadata").get_value_or(nullptr);
57
  f_get_all_domain_metadata = d_lw->readVariable<boost::optional<get_all_domain_metadata_call_t>>("dns_get_all_domain_metadata").get_value_or(nullptr);
58
  f_get_domain_keys = d_lw->readVariable<boost::optional<get_domain_keys_call_t>>("dns_get_domain_keys").get_value_or(nullptr);
59
  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(nullptr);
60
  f_set_notified = d_lw->readVariable<boost::optional<set_notified_call_t>>("dns_set_notified").get_value_or(nullptr);
61

62
  auto init = d_lw->readVariable<boost::optional<init_call_t>>("dns_init").get_value_or(nullptr);
63
  if (init) {
64
    init();
65
  }
66

67
  f_deinit = d_lw->readVariable<boost::optional<deinit_call_t>>("dns_deinit").get_value_or(nullptr);
68

69
  if (f_lookup == nullptr) {
70
    throw PDNSException("dns_lookup missing");
71
  }
72

73
  /* see if dnssec support is wanted */
74
  d_dnssec = d_lw->readVariable<boost::optional<bool>>("dns_dnssec").get_value_or(false);
75
  if (d_dnssec) {
76
    if (f_get_domain_metadata == nullptr) {
77
      throw PDNSException("dns_dnssec is true but dns_get_domain_metadata is missing");
78
    }
79
    if (f_get_before_and_after_names_absolute == nullptr) {
80
      throw PDNSException("dns_dnssec is true but dns_get_before_and_after_names_absolute is missing");
81
    }
82
    /* domain keys is not strictly speaking necessary for dnssec backend */
83
    if (f_get_domain_keys == nullptr) {
84
      SLOG(g_log << Logger::Warning << "dns_get_domain_keys missing - cannot do live signing" << endl,
85
           d_slog->info(Logr::Warning, "dns_get_domain_keys missing - cannot perform live signing"));
86
    }
87
  }
88
}
89

90
unsigned int Lua2BackendAPIv2::getCapabilities()
91
{
92
  unsigned int caps = CAP_DIRECT | CAP_LIST;
93
  if (d_dnssec) {
94
    caps |= CAP_DNSSEC;
95
  }
96
  if (f_get_all_domains != nullptr) {
97
    caps |= CAP_SEARCH;
98
  }
99
  return caps;
100
}
101

102
void Lua2BackendAPIv2::parseLookup(const lookup_result_t& result)
103
{
104
  for (const auto& row : result) {
105
    DNSResourceRecord rec;
106
    for (const auto& item : row.second) {
107
      try {
108
        if (item.first == "type") {
109
          if (item.second.which() == 1) {
110
            rec.qtype = QType(boost::get<int>(item.second));
111
          }
112
          else if (item.second.which() == 3) {
113
            rec.qtype = boost::get<string>(item.second);
114
          }
115
          else if (item.second.which() == 4) {
116
            rec.qtype = boost::get<QType>(item.second);
117
          }
118
          else {
119
            throw PDNSException("Unsupported value for type");
120
          }
121
        }
122
        else if (item.first == "name") {
123
          if (item.second.which() == 3) {
124
            rec.qname = DNSName(boost::get<string>(item.second));
125
          }
126
          else { // assuming item.second.which() == 2 here
127
            rec.qname = boost::get<DNSName>(item.second);
128
          }
129
        }
130
        else if (item.first == "domain_id") {
131
          rec.domain_id = boost::get<int>(item.second);
132
        }
133
        else if (item.first == "auth") {
134
          rec.auth = boost::get<bool>(item.second);
135
        }
136
        else if (item.first == "last_modified") {
137
          rec.last_modified = static_cast<time_t>(boost::get<int>(item.second));
138
        }
139
        else if (item.first == "ttl") {
140
          rec.ttl = boost::get<int>(item.second);
141
        }
142
        else if (item.first == "content") {
143
          if (item.second.which() == 1) {
144
            rec.setContent(std::to_string(boost::get<int>(item.second)));
145
          }
146
          else { // assuming item.second.which() == 3 here
147
            rec.setContent(boost::get<string>(item.second));
148
          }
149
        }
150
        else if (item.first == "scopeMask") {
151
          rec.scopeMask = boost::get<int>(item.second);
152
        }
153
        else {
154
          SLOG(g_log << Logger::Warning << "Unsupported key '" << item.first << "' in lookup or list result" << endl,
155
               d_slog->info(Logr::Warning, "Unsupported key in lookup or list result", "key", Logging::Loggable(item.first)));
156
        }
157
      }
158
      catch (const std::exception& e) {
159
        throw PDNSException("Unable to parse " + item.first + " value in lookup or list result: " + e.what());
160
      }
161
    }
162
    if (d_debug_log) {
163
      SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Got result " << "'" << rec.qname << " IN " << rec.qtype.toString() << " " << rec.ttl << " " << rec.getZoneRepresentation() << "'" << endl,
164
           d_slog->info(Logr::Debug, "Got result", "name", Logging::Loggable(rec.qname), "type", Logging::Loggable(rec.qtype), "ttl", Logging::Loggable(rec.ttl), "data", Logging::Loggable(rec.getZoneRepresentation())));
165
    }
166
    d_result.push_back(std::move(rec));
167
  }
168
  if (d_result.empty() && d_debug_log) {
169
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Got empty result" << endl,
170
         d_slog->info(Logr::Debug, "Got empty result"));
171
  }
172
}
173

174
bool Lua2BackendAPIv2::list(const ZoneName& target, domainid_t domain_id, bool /* include_disabled */)
175
{
176
  if (f_list == nullptr) {
177
    SLOG(g_log << Logger::Error << "[" << getPrefix() << "] dns_list missing - cannot do AXFR" << endl,
178
         d_slog->info(Logr::Error, "dns_list missing - cannot perform AXFR"));
179
    return false;
180
  }
181

182
  if (!d_result.empty()) {
183
    throw PDNSException("list attempted while another was running");
184
  }
185

186
  if (d_debug_log) {
187
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Calling " << "list" << "(" << "target=" << target << ",domain_id=" << domain_id << ")" << endl,
188
         d_slog->info(Logr::Debug, "Calling list", "target", Logging::Loggable(target), "domain id", Logging::Loggable(domain_id)));
189
  }
190
  list_result_t result = f_list(target.operator const DNSName&(), domain_id);
191

192
  if (result.which() == 0) {
193
    return false;
194
  }
195

196
  parseLookup(boost::get<lookup_result_t>(result));
197

198
  return true;
199
}
200

201
void Lua2BackendAPIv2::lookup(const QType& qtype, const DNSName& qname, domainid_t domain_id, DNSPacket* pkt)
202
{
203
  if (!d_result.empty()) {
204
    throw PDNSException("lookup attempted while another was running");
205
  }
206

207
  lookup_context_t ctx;
208
  if (pkt != nullptr) {
209
    ctx.emplace_back(lookup_context_t::value_type{"source_address", pkt->getInnerRemote().toString()});
210
    ctx.emplace_back(lookup_context_t::value_type{"real_source_address", pkt->getRealRemote().toString()});
211
  }
212

213
  if (d_debug_log) {
214
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Calling " << "lookup" << "(" << "qtype=" << qtype.toString() << ",qname=" << qname << ",domain_id=" << domain_id << ")" << endl,
215
         d_slog->info(Logr::Debug, "Calling lookup", "type", Logging::Loggable(qtype), "name", Logging::Loggable(qname), "domain id", Logging::Loggable(domain_id)));
216
  }
217
  lookup_result_t result = f_lookup(qtype, qname, domain_id, ctx);
218
  parseLookup(result);
219
}
220

221
bool Lua2BackendAPIv2::get(DNSResourceRecord& drr)
222
{
223
  if (d_result.empty()) {
224
    return false;
225
  }
226
  drr = std::move(d_result.front());
227
  d_result.pop_front();
228
  return true;
229
}
230

231
string Lua2BackendAPIv2::directBackendCmd(const string& querystr)
232
{
233
  string::size_type pos = querystr.find_first_of(" \t");
234
  string cmd = querystr;
235
  string par{};
236
  if (pos != string::npos) {
237
    cmd = querystr.substr(0, pos);
238
    par = querystr.substr(pos + 1);
239
  }
240
  direct_backend_cmd_call_t dbc = d_lw->readVariable<boost::optional<direct_backend_cmd_call_t>>(cmd).get_value_or(nullptr);
241
  if (dbc == nullptr) {
242
    return cmd + "not found";
243
  }
244
  if (d_debug_log) {
245
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Calling " << cmd << "(" << "parameter=" << par << ")" << endl,
246
         d_slog->info(Logr::Debug, "Direct backend command", "command", Logging::Loggable(cmd), "parameters", Logging::Loggable(par)));
247
  }
248
  return dbc(par);
249
}
250

251
void Lua2BackendAPIv2::setNotified(domainid_t domain_id, uint32_t serial)
252
{
253
  if (f_set_notified == nullptr) {
254
    return;
255
  }
256
  if (d_debug_log) {
257
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Calling " << "dns_set_notified" << "(" << "id=" << domain_id << ",serial=" << serial << ")" << endl,
258
         d_slog->info(Logr::Debug, "Calling dns_set_notified", "id", Logging::Loggable(domain_id), "serial", Logging::Loggable(serial)));
259
  }
260
  f_set_notified(domain_id, serial);
261
}
262

263
void Lua2BackendAPIv2::parseDomainInfo(const domaininfo_result_t& row, DomainInfo& info)
264
{
265
  info.id = UnknownDomainID;
266
  for (const auto& item : row) {
267
    try {
268
      if (item.first == "account") {
269
        if (item.second.which() == 1) { // should the account name be all-digits...
270
          info.account = std::to_string(boost::get<long>(item.second));
271
        }
272
        else { // assuming item.second.which() == 2 here
273
          info.account = boost::get<string>(item.second);
274
        }
275
      }
276
      else if (item.first == "last_check") {
277
        info.last_check = static_cast<time_t>(boost::get<long>(item.second));
278
      }
279
      else if (item.first == "masters") {
280
        for (const auto& primary : boost::get<vector<string>>(item.second)) {
281
          info.primaries.emplace_back(ComboAddress(primary, 53));
282
        }
283
      }
284
      else if (item.first == "id") {
285
        info.id = static_cast<domainid_t>(boost::get<long>(item.second));
286
      }
287
      else if (item.first == "notified_serial") {
288
        info.notified_serial = static_cast<unsigned int>(boost::get<long>(item.second));
289
      }
290
      else if (item.first == "serial") {
291
        info.serial = static_cast<unsigned int>(boost::get<long>(item.second));
292
      }
293
      else if (item.first == "kind") {
294
        info.kind = DomainInfo::stringToKind(boost::get<string>(item.second));
295
      }
296
      else {
297
        SLOG(g_log << Logger::Warning << "Unsupported key '" << item.first << "' in domaininfo result" << endl,
298
             d_slog->info(Logr::Warning, "Unsupported key in domaininfo result", "key", Logging::Loggable(item.first)));
299
      }
300
    }
301
    catch (const std::exception& e) {
302
      throw PDNSException("Unable to parse " + item.first + " value in domaininfo result: " + e.what());
303
    }
304
  }
305
  info.backend = this;
306
  if (d_debug_log) {
307
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Got result " << "'" << "zone=" << info.zone << ",serial=" << info.serial << ",kind=" << info.getKindString() << "'" << endl,
308
         d_slog->info(Logr::Debug, "Got domain info", "zone", Logging::Loggable(info.zone), "serial", Logging::Loggable(info.serial), "kind", Logging::Loggable(info.getKindString())));
309
  }
310
}
311

312
bool Lua2BackendAPIv2::getDomainInfo(const ZoneName& domain, DomainInfo& info, bool /* getSerial */)
313
{
314
  if (f_get_domaininfo == nullptr) {
315
    // use getAuth instead... but getAuth wraps getSOA which will call
316
    // getDomainInfo if this is a domain variant, so protect against this
317
    // would-be infinite recursion.
318
    if (domain.hasVariant()) {
319
      SLOG(g_log << Logger::Info << "Unable to return domain information for '" << domain.toLogString() << "' due to unimplemented dns_get_domaininfo" << endl,
320
           d_slog->info(Logr::Info, "Unable to return domain information due to unimplemented dns_get_domaininfo", "domain", Logging::Loggable(domain)));
321
      return false;
322
    }
323
    SOAData soa;
324
    if (!getAuth(domain, &soa)) {
325
      return false;
326
    }
327

328
    info.id = soa.domain_id;
329
    info.zone = domain;
330
    info.backend = this;
331
    info.serial = soa.serial;
332
    return true;
333
  }
334

335
  if (d_debug_log) {
336
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Calling " << "get_domaininfo" << "(" << "domain=" << domain << ")" << endl,
337
         d_slog->info(Logr::Debug, "Calling get_domaininfo", "domain", Logging::Loggable(domain)));
338
  }
339
  get_domaininfo_result_t result = f_get_domaininfo(domain.operator const DNSName&());
340

341
  if (result.which() == 0) {
342
    return false;
343
  }
344

345
  info.zone = domain;
346
  parseDomainInfo(boost::get<domaininfo_result_t>(result), info);
347

348
  return true;
349
}
350

351
void Lua2BackendAPIv2::getAllDomains(vector<DomainInfo>* domains, bool /* getSerial */, bool /* include_disabled */)
352
{
353
  if (f_get_all_domains == nullptr) {
354
    return;
355
  }
356

357
  if (d_debug_log) {
358
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Calling " << "get_all_domains" << "(" << "" << ")" << endl,
359
         d_slog->info(Logr::Debug, "Calling get_all_domains"));
360
  }
361
  for (const auto& row : f_get_all_domains()) {
362
    DomainInfo info;
363
    info.zone = ZoneName(row.first);
364
    if (d_debug_log) {
365
      SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Got result " << "'" << info.zone << "'" << endl,
366
           d_slog->info(Logr::Debug, "Got result", "domain", Logging::Loggable(info.zone)));
367
    }
368
    parseDomainInfo(row.second, info);
369
    domains->push_back(std::move(info));
370
  }
371
}
372

373
bool Lua2BackendAPIv2::getAllDomainMetadata(const ZoneName& name, std::map<std::string, std::vector<std::string>>& meta)
374
{
375
  if (f_get_all_domain_metadata == nullptr) {
376
    return false;
377
  }
378

379
  if (d_debug_log) {
380
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Calling " << "get_all_domain_metadata" << "(" << "name=" << name << ")" << endl,
381
         d_slog->info(Logr::Debug, "Calling get_all_domain_metadata", "domain", Logging::Loggable(name)));
382
  }
383
  get_all_domain_metadata_result_t result = f_get_all_domain_metadata(name.operator const DNSName&());
384
  if (result.which() == 0) {
385
    return false;
386
  }
387

388
  for (const auto& row : boost::get<vector<pair<string, domain_metadata_result_t>>>(result)) {
389
    meta[row.first].clear();
390
    for (const auto& item : row.second) {
391
      meta[row.first].push_back(item.second);
392
    }
393
    if (d_debug_log) {
394
      SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Got result " << "'" << "kind=" << row.first << ",value=" << boost::algorithm::join(meta[row.first], ", ") << "'" << endl,
395
           d_slog->info(Logr::Debug, "Got result", "kind", Logging::Loggable(row.first), "value", Logging::Loggable(boost::algorithm::join(meta[row.first], ", "))));
396
    }
397
  }
398

399
  return true;
400
}
401

402
bool Lua2BackendAPIv2::getDomainMetadata(const ZoneName& name, const std::string& kind, std::vector<std::string>& meta)
403
{
404
  if (f_get_domain_metadata == nullptr) {
405
    return false;
406
  }
407

408
  if (d_debug_log) {
409
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Calling " << "get_domain_metadata" << "(" << "name=" << name << ",kind=" << kind << ")" << endl,
410
         d_slog->info(Logr::Debug, "Calling get_domain_metadata", "domain", Logging::Loggable(name), "kind", Logging::Loggable(kind)));
411
  }
412
  get_domain_metadata_result_t result = f_get_domain_metadata(name.operator const DNSName&(), kind);
413
  if (result.which() == 0) {
414
    return false;
415
  }
416

417
  meta.clear();
418
  for (const auto& item : boost::get<domain_metadata_result_t>(result)) {
419
    meta.push_back(item.second);
420
  }
421

422
  if (d_debug_log) {
423
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Got result " << "'" << "value=" << boost::algorithm::join(meta, ", ") << "'" << endl,
424
         d_slog->info(Logr::Debug, "Got result", "value", Logging::Loggable(boost::algorithm::join(meta, ", "))));
425
  }
426
  return true;
427
}
428

429
bool Lua2BackendAPIv2::getDomainKeys(const ZoneName& name, std::vector<DNSBackend::KeyData>& keys)
430
{
431
  if (f_get_domain_keys == nullptr) {
432
    return false;
433
  }
434

435
  if (d_debug_log) {
436
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Calling " << "get_domain_keys" << "(" << "name=" << name << ")" << endl,
437
         d_slog->info(Logr::Debug, "Calling get_domain_keys", "domain", Logging::Loggable(name)));
438
  }
439
  get_domain_keys_result_t result = f_get_domain_keys(name.operator const DNSName&());
440

441
  if (result.which() == 0) {
442
    return false;
443
  }
444

445
  for (const auto& row : boost::get<vector<pair<int, keydata_result_t>>>(result)) {
446
    DNSBackend::KeyData key;
447
    key.published = true;
448
    for (const auto& item : row.second) {
449
      try {
450
        if (item.first == "content") {
451
          key.content = boost::get<string>(item.second);
452
        }
453
        else if (item.first == "id") {
454
          key.id = static_cast<unsigned int>(boost::get<int>(item.second));
455
        }
456
        else if (item.first == "flags") {
457
          key.flags = static_cast<unsigned int>(boost::get<int>(item.second));
458
        }
459
        else if (item.first == "active") {
460
          key.active = boost::get<bool>(item.second);
461
        }
462
        else if (item.first == "published") {
463
          key.published = boost::get<bool>(item.second);
464
        }
465
        else {
466
          SLOG(g_log << Logger::Warning << "[" << getPrefix() << "] Unsupported key '" << item.first << "' in keydata result" << endl,
467
               d_slog->info(Logr::Warning, "Unsupported key in keydata result", "key", Logging::Loggable(item.first)));
468
        }
469
      }
470
      catch (const std::exception& e) {
471
        throw PDNSException("Unable to parse " + item.first + " value in keydata result: " + e.what());
472
      }
473
    }
474
    if (d_debug_log) {
475
      SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Got result " << "'" << "id=" << key.id << ",flags=" << key.flags << ",active=" << (key.active ? "true" : "false") << ",published=" << (key.published ? "true" : "false") << "'" << endl,
476
           d_slog->info(Logr::Debug, "Got result", "id", Logging::Loggable(key.id), "flags", Logging::Loggable(key.flags), "active", Logging::Loggable(key.active ? "true" : "false"), "published", Logging::Loggable(key.published ? "true" : "false")));
477
    }
478
    keys.emplace_back(std::move(key));
479
  }
480

481
  return true;
482
}
483

484
bool Lua2BackendAPIv2::getBeforeAndAfterNamesAbsolute(domainid_t domain_id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after)
485
{
486
  if (f_get_before_and_after_names_absolute == nullptr) {
487
    return false;
488
  }
489

490
  if (d_debug_log) {
491
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Calling " << "get_before_and_after_names_absolute" << "(" << "id=<<" << domain_id << ",qname=" << qname << ")" << endl,
492
         d_slog->info(Logr::Debug, "Calling get_before_and_after_names_absolute", "id", Logging::Loggable(domain_id), "name", Logging::Loggable(qname)));
493
  }
494
  get_before_and_after_names_absolute_result_t result = f_get_before_and_after_names_absolute(domain_id, qname);
495

496
  if (result.which() == 0) {
497
    return false;
498
  }
499

500
  before_and_after_names_result_t row = boost::get<before_and_after_names_result_t>(result);
501
  if (row.size() != 3) {
502
    SLOG(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,
503
         d_slog->info(Logr::Error, "Invalid result from dns_get_before_and_after_names_absolute, expected array with 3 rows", "rows returned", Logging::Loggable(row.size())));
504
    return false;
505
  }
506
  for (const auto& item : row) {
507
    DNSName value;
508
    if (item.second.which() == 0) {
509
      value = DNSName(boost::get<string>(item.second));
510
    }
511
    else {
512
      value = DNSName(boost::get<DNSName>(item.second));
513
    }
514
    if (item.first == "unhashed") {
515
      unhashed = std::move(value);
516
    }
517
    else if (item.first == "before") {
518
      before = std::move(value);
519
    }
520
    else if (item.first == "after") {
521
      after = std::move(value);
522
    }
523
    else {
524
      SLOG(g_log << Logger::Error << "Invalid result from dns_get_before_and_after_names_absolute, unexpected key " << item.first << endl,
525
           d_slog->info(Logr::Error, "Invalid result from dns_get_before_and_after_names_absolute, unexpected key", "key", Logging::Loggable(item.first)));
526
      return false;
527
    }
528
  }
529

530
  if (d_debug_log) {
531
    SLOG(g_log << Logger::Debug << "[" << getPrefix() << "] Got result " << "'" << "unhashed=" << unhashed << ",before=" << before << ",after=" << after << "'" << endl,
532
         d_slog->info(Logr::Debug, "Got result", "unhashed", Logging::Loggable(unhashed), "before", Logging::Loggable(before), "after", Logging::Loggable(after)));
533
  }
534
  return true;
535
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc