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

PowerDNS / pdns / 18743945403

23 Oct 2025 09:29AM UTC coverage: 65.845% (+0.02%) from 65.829%
18743945403

Pull #16356

github

web-flow
Merge 8a2027ef1 into efa3637e8
Pull Request #16356: auth 5.0: backport "pdnsutil: fix b2b-migrate to from sql to non-sql"

42073 of 92452 branches covered (45.51%)

Branch coverage included in aggregate %.

128008 of 165855 relevant lines covered (77.18%)

6379935.17 hits per line

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

49.5
/pdns/recursordist/reczones.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

23
#ifdef HAVE_CONFIG_H
24
#include "config.h"
25
#endif
26

27
#include <sys/stat.h>
28

29
#include "reczones-helpers.hh"
30
#include "arguments.hh"
31
#include "dnsrecords.hh"
32
#include "logger.hh"
33
#include "syncres.hh"
34
#include "zoneparser-tng.hh"
35
#include "rec-rust-lib/cxxsettings.hh"
36
#include "rec-system-resolve.hh"
37
#include "rec-main.hh"
38

39
bool primeHints(time_t now)
40
{
322✔
41
  const string hintfile = ::arg()["hint-file"];
322✔
42
  vector<DNSRecord> nsvec;
322✔
43
  bool ret = true;
322✔
44

45
  if (hintfile == "no" || hintfile == "no-refresh") {
322!
46
    auto log = g_slog->withName("config");
×
47
    SLOG(g_log << Logger::Debug << "Priming root disabled by hint-file setting" << endl,
×
48
         log->info(Logr::Debug, "Priming root disabled by hint-file setting"));
×
49
    return ret;
×
50
  }
×
51

52
  if (hintfile.empty()) {
322✔
53
    putDefaultHintsIntoCache(now, nsvec);
24✔
54
  }
24✔
55
  else {
298✔
56
    ret = readHintsIntoCache(now, hintfile, nsvec);
298✔
57
  }
298✔
58

59
  g_recCache->doWipeCache(g_rootdnsname, false, QType::NS);
322✔
60
  g_recCache->replace(now, g_rootdnsname, QType::NS, nsvec, {}, {}, false, g_rootdnsname, boost::none, boost::none, vState::Insecure, ComboAddress("255.255.255.255")); // and stuff in the cache
322✔
61
  return ret;
322✔
62
}
322✔
63

64
static void convertServersForAD(const std::string& zone, const std::string& input, SyncRes::AuthDomain& authDomain, const char* sepa, Logr::log_t log, bool verbose = true)
65
{
47✔
66
  vector<string> servers;
47✔
67
  stringtok(servers, input, sepa);
47✔
68
  if (servers.empty()) {
47!
69
    throw PDNSException("empty list of forwarders for domain '" + zone + '"');
×
70
  }
×
71
  authDomain.d_servers.clear();
47✔
72

73
  vector<string> addresses;
47✔
74
  for (auto& server : servers) {
51✔
75
    ComboAddress addr = pdns::fromNameOrIP(server, 53, log);
51✔
76
    authDomain.d_servers.push_back(addr);
51✔
77
    if (verbose) {
51!
78
      addresses.push_back(addr.toStringWithPort());
51✔
79
    }
51✔
80
  }
51✔
81
  if (verbose) {
47!
82
    if (!g_slogStructured) {
47✔
83
      g_log << Logger::Info << "Redirecting queries for zone '" << zone << "' ";
×
84
      if (authDomain.d_rdForward) {
×
85
        g_log << "with recursion ";
×
86
      }
×
87
      g_log << "to: ";
×
88
      bool first = true;
×
89
      for (const auto& address : addresses) {
×
90
        if (!first) {
×
91
          g_log << ", ";
×
92
        }
×
93
        else {
×
94
          first = false;
×
95
        }
×
96
        g_log << address;
×
97
      }
×
98
      g_log << endl;
×
99
    }
×
100
    else {
47✔
101
      log->info(Logr::Info, "Redirecting queries", "zone", Logging::Loggable(zone), "recursion", Logging::Loggable(authDomain.d_rdForward), "addresses", Logging::IterLoggable(addresses.begin(), addresses.end()));
47✔
102
    }
47✔
103
  }
47✔
104
}
47✔
105

106
static void* pleaseUseNewSDomainsMap(std::shared_ptr<SyncRes::domainmap_t> newmap)
107
{
50✔
108
  SyncRes::setDomainMap(std::move(newmap));
50✔
109
  return nullptr;
50✔
110
}
50✔
111

112
string reloadZoneConfiguration(bool yaml)
113
{
10✔
114
  auto log = g_slog->withName("config");
10✔
115

116
  string configname = ::arg()["config-dir"] + "/recursor";
10✔
117
  if (!::arg()["config-name"].empty()) {
10!
118
    configname = ::arg()["config-dir"] + "/recursor-" + ::arg()["config-name"];
×
119
  }
×
120
  cleanSlashes(configname);
10✔
121

122
  try {
10✔
123
    SLOG(g_log << Logger::Warning << "Reloading zones, purging data from cache" << endl,
10✔
124
         log->info(Logr::Notice, "Reloading zones, purging data from cache"));
10✔
125

126
    if (yaml) {
10!
127
      configname += g_yamlSettingsSuffix;
10✔
128
      string msg;
10✔
129
      pdns::rust::settings::rec::Recursorsettings settings;
10✔
130
      // XXX Does ::arg()["include-dir"] have the right value, i.e. potentially overriden by command line?
131
      auto yamlstatus = pdns::settings::rec::readYamlSettings(configname, ::arg()["include-dir"], settings, msg, log);
10✔
132

133
      switch (yamlstatus) {
10!
134
      case pdns::settings::rec::YamlSettingsStatus::CannotOpen:
×
135
        throw runtime_error("Unable to open '" + configname + "': " + msg);
×
136
        break;
×
137
      case pdns::settings::rec::YamlSettingsStatus::PresentButFailed:
×
138
        throw runtime_error("Error processing '" + configname + "': " + msg);
×
139
        break;
×
140
      case pdns::settings::rec::YamlSettingsStatus::OK:
10!
141
        // Does *not* set include-dir
142
        pdns::settings::rec::setArgsForZoneRelatedSettings(settings);
10✔
143
        break;
10✔
144
      }
10✔
145
    }
10✔
146
    else {
×
147
      configname += ".conf";
×
148

149
      if (!::arg().preParseFile(configname, "forward-zones")) {
×
150
        throw runtime_error("Unable to re-parse configuration file '" + configname + "'");
×
151
      }
×
152
      ::arg().preParseFile(configname, "forward-zones-file");
×
153
      ::arg().preParseFile(configname, "forward-zones-recurse");
×
154
      ::arg().preParseFile(configname, "auth-zones");
×
155
      ::arg().preParseFile(configname, "allow-notify-for");
×
156
      ::arg().preParseFile(configname, "allow-notify-for-file");
×
157
      ::arg().preParseFile(configname, "export-etc-hosts", "off");
×
158
      ::arg().preParseFile(configname, "serve-rfc1918");
×
159
      ::arg().preParseFile(configname, "serve-rfc6303");
×
160
      ::arg().preParseFile(configname, "include-dir");
×
161
      ::arg().preParse(g_argc, g_argv, "include-dir");
×
162

163
      // then process includes
164
      std::vector<std::string> extraConfigs;
×
165
      ::arg().gatherIncludes(::arg()["include-dir"], ".conf", extraConfigs);
×
166

167
      for (const std::string& filename : extraConfigs) {
×
168
        if (!::arg().preParseFile(filename, "forward-zones", ::arg()["forward-zones"])) {
×
169
          throw runtime_error("Unable to re-parse configuration file include '" + filename + "'");
×
170
        }
×
171
        ::arg().preParseFile(filename, "forward-zones-file", ::arg()["forward-zones-file"]);
×
172
        ::arg().preParseFile(filename, "forward-zones-recurse", ::arg()["forward-zones-recurse"]);
×
173
        ::arg().preParseFile(filename, "auth-zones", ::arg()["auth-zones"]);
×
174
        ::arg().preParseFile(filename, "allow-notify-for", ::arg()["allow-notify-for"]);
×
175
        ::arg().preParseFile(filename, "allow-notify-for-file", ::arg()["allow-notify-for-file"]);
×
176
        ::arg().preParseFile(filename, "export-etc-hosts", ::arg()["export-etc-hosts"]);
×
177
        ::arg().preParseFile(filename, "serve-rfc1918", ::arg()["serve-rfc1918"]);
×
178
        ::arg().preParseFile(filename, "serve-rfc6303", ::arg()["serve-rfc6303"]);
×
179
      }
×
180
    }
×
181
    // Process command line args potentially overriding what we read from config files
182
    ::arg().preParse(g_argc, g_argv, "forward-zones");
10✔
183
    ::arg().preParse(g_argc, g_argv, "forward-zones-file");
10✔
184
    ::arg().preParse(g_argc, g_argv, "forward-zones-recurse");
10✔
185
    ::arg().preParse(g_argc, g_argv, "auth-zones");
10✔
186
    ::arg().preParse(g_argc, g_argv, "allow-notify-for");
10✔
187
    ::arg().preParse(g_argc, g_argv, "allow-notify-for-file");
10✔
188
    ::arg().preParse(g_argc, g_argv, "export-etc-hosts");
10✔
189
    ::arg().preParse(g_argc, g_argv, "serve-rfc1918");
10✔
190
    ::arg().preParse(g_argc, g_argv, "serve-rfc6303");
10✔
191

192
    auto [newDomainMap, newNotifySet] = parseZoneConfiguration(yaml);
10✔
193

194
    // purge both original and new names
195
    std::set<DNSName> oldAndNewDomains;
10✔
196
    for (const auto& entry : *newDomainMap) {
337✔
197
      oldAndNewDomains.insert(entry.first);
337✔
198
    }
337✔
199

200
    {
10✔
201
      auto lock = g_initialDomainMap.lock();
10✔
202
      if (*lock) {
10!
203
        for (const auto& entry : **lock) {
336✔
204
          oldAndNewDomains.insert(entry.first);
336✔
205
        }
336✔
206
      }
10✔
207
    }
10✔
208

209
    // these explicitly-named captures should not be necessary, as lambda
210
    // capture of tuple-like structured bindings is permitted, but some
211
    // compilers still don't allow it
212
    broadcastFunction([dmap = newDomainMap] { return pleaseUseNewSDomainsMap(dmap); });
50✔
213
    broadcastFunction([nsset = newNotifySet] { return pleaseSupplantAllowNotifyFor(nsset); });
50✔
214

215
    // Wipe the caches *after* the new auth domain info has been set
216
    // up, as a query during setting up might fill the caches
217
    // again. Old code did the clear before, exposing a race.
218
    for (const auto& entry : oldAndNewDomains) {
349✔
219
      wipeCaches(entry, true, 0xffff);
349✔
220
    }
349✔
221
    *g_initialDomainMap.lock() = std::move(newDomainMap);
10✔
222
    *g_initialAllowNotifyFor.lock() = std::move(newNotifySet);
10✔
223
    return "ok\n";
10✔
224
  }
10✔
225
  catch (const std::exception& e) {
10✔
226
    SLOG(g_log << Logger::Error << "Encountered error reloading zones, keeping original data: " << e.what() << endl,
×
227
         log->error(Logr::Error, e.what(), "Encountered error reloading zones, keeping original data"));
×
228
  }
×
229
  catch (const PDNSException& ae) {
10✔
230
    SLOG(g_log << Logger::Error << "Encountered error reloading zones, keeping original data: " << ae.reason << endl,
×
231
         log->error(Logr::Error, ae.reason, "Encountered error reloading zones, keeping original data"));
×
232
  }
×
233
  catch (...) {
10✔
234
    SLOG(g_log << Logger::Error << "Encountered unknown error reloading zones, keeping original data" << endl,
×
235
         log->error(Logr::Error, "Exception", "Encountered error reloading zones, keeping original data"));
×
236
  }
×
237
  return "reloading failed, see log\n";
×
238
}
10✔
239

240
static void readAuthZoneData(SyncRes::AuthDomain& authDomain, const pair<string, string>& headers, Logr::log_t log)
241
{
44✔
242
  SLOG(g_log << Logger::Notice << "Parsing authoritative data for zone '" << headers.first << "' from file '" << headers.second << "'" << endl,
44✔
243
       log->info(Logr::Notice, "Parsing authoritative data from file", "zone", Logging::Loggable(headers.first), "file", Logging::Loggable(headers.second)));
44✔
244
  ZoneParserTNG zpt(headers.second, DNSName(headers.first));
44✔
245
  zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
44✔
246
  zpt.setMaxIncludes(::arg().asNum("max-include-depth"));
44✔
247
  DNSResourceRecord resourceRecord;
44✔
248
  DNSRecord dnsrecord;
44✔
249
  while (zpt.get(resourceRecord)) {
438✔
250
    try {
394✔
251
      dnsrecord = DNSRecord(resourceRecord);
394✔
252
      dnsrecord.d_place = DNSResourceRecord::ANSWER;
394✔
253
    }
394✔
254
    catch (std::exception& e) {
394✔
255
      throw PDNSException("Error parsing record '" + resourceRecord.qname.toLogString() + "' of type " + resourceRecord.qtype.toString() + " in zone '" + headers.first + "' from file '" + headers.second + "': " + e.what());
×
256
    }
×
257
    catch (...) {
394✔
258
      throw PDNSException("Error parsing record '" + resourceRecord.qname.toLogString() + "' of type " + resourceRecord.qtype.toString() + " in zone '" + headers.first + "' from file '" + headers.second + "'");
×
259
    }
×
260

261
    authDomain.d_records.insert(dnsrecord);
394✔
262
  }
394✔
263
}
44✔
264

265
static void processForwardZones(shared_ptr<SyncRes::domainmap_t>& newMap, Logr::log_t log)
266
{
185✔
267
  const std::array<string, 3> option_names = {"auth-zones", "forward-zones", "forward-zones-recurse"};
185✔
268

269
  for (size_t option = 0; option < option_names.size(); ++option) {
740✔
270
    vector<string> parts;
555✔
271
    stringtok(parts, ::arg()[option_names.at(option)], " ,\t\n\r");
555✔
272
    for (const auto& part : parts) {
555✔
273
      SyncRes::AuthDomain authDomain;
91✔
274
      if (part.find('=') == string::npos) {
91!
275
        throw PDNSException("Error parsing '" + part + "', missing =");
×
276
      }
×
277
      pair<string, string> headers = splitField(part, '=');
91✔
278
      boost::trim(headers.first);
91✔
279
      boost::trim(headers.second);
91✔
280

281
      if (option == 0) {
91✔
282
        authDomain.d_rdForward = false;
44✔
283
        readAuthZoneData(authDomain, headers, log);
44✔
284
      }
44✔
285
      else {
47✔
286
        authDomain.d_rdForward = (option == 2);
47✔
287
        convertServersForAD(headers.first, headers.second, authDomain, ";", log);
47✔
288
      }
47✔
289

290
      authDomain.d_name = DNSName(headers.first);
91✔
291
      (*newMap)[authDomain.d_name] = authDomain;
91✔
292
    }
91✔
293
  }
555✔
294
}
185✔
295

296
static void processApiZonesFile(const string& file, shared_ptr<SyncRes::domainmap_t>& newMap, shared_ptr<notifyset_t>& newSet, Logr::log_t log)
297
{
28✔
298
  if (::arg()["api-config-dir"].empty()) {
28✔
299
    return;
5✔
300
  }
5✔
301
  const auto filename = ::arg()["api-config-dir"] + "/" + file;
23✔
302
  struct stat statStruct{};
23✔
303
  // It's a TOCTU, but a harmless one
304
  if (stat(filename.c_str(), &statStruct) != 0) {
23✔
305
    return;
1✔
306
  }
1✔
307

308
  SLOG(g_log << Logger::Notice << "Processing ApiZones YAML settings from " << filename << endl,
22✔
309
       log->info(Logr::Notice, "Processing ApiZones YAML settings", "path", Logging::Loggable(filename)));
22✔
310

311
  const uint64_t before = newMap->size();
22✔
312

313
  std::unique_ptr<pdns::rust::settings::rec::ApiZones> zones = pdns::rust::settings::rec::api_read_zones(filename);
22✔
314
  zones->validate("apizones");
22✔
315

316
  for (const auto& forward : zones->forward_zones) {
1,376✔
317
    SyncRes::AuthDomain authDomain;
1,376✔
318
    authDomain.d_name = DNSName(string(forward.zone));
1,376✔
319
    authDomain.d_rdForward = forward.recurse;
1,376✔
320
    for (const auto& forwarder : forward.forwarders) {
2,741✔
321
      ComboAddress addr = pdns::fromNameOrIP(string(forwarder), 53, log);
2,741✔
322
      authDomain.d_servers.emplace_back(addr);
2,741✔
323
    }
2,741✔
324
    (*newMap)[authDomain.d_name] = authDomain;
1,376✔
325
    if (forward.notify_allowed) {
1,376✔
326
      newSet->insert(authDomain.d_name);
1✔
327
    }
1✔
328
  }
1,376✔
329
  for (const auto& auth : zones->auth_zones) {
22!
330
    SyncRes::AuthDomain authDomain;
×
331
    authDomain.d_name = DNSName(string(auth.zone));
×
332
    readAuthZoneData(authDomain, {string(auth.zone), string(auth.file)}, log);
×
333
    (*newMap)[authDomain.d_name] = authDomain;
×
334
  }
×
335
  SLOG(g_log << Logger::Warning << "Done parsing " << newMap->size() - before
22✔
336
             << " ApiZones YAML settings from file '"
22✔
337
             << filename << "'" << endl,
22✔
338
       log->info(Logr::Notice, "Done parsing ApiZones YAML from file", "file",
22✔
339
                 Logging::Loggable(filename), "count",
22✔
340
                 Logging::Loggable(newMap->size() - before)));
22✔
341
}
22✔
342

343
static void processForwardZonesFile(shared_ptr<SyncRes::domainmap_t>& newMap, shared_ptr<notifyset_t>& newSet, Logr::log_t log)
344
{
185✔
345
  const auto& filename = ::arg()["forward-zones-file"];
185✔
346
  if (filename.empty()) {
185!
347
    return;
185✔
348
  }
185✔
349
  const uint64_t before = newMap->size();
×
350

351
  if (boost::ends_with(filename, ".yml")) {
×
352
    ::rust::Vec<pdns::rust::settings::rec::ForwardZone> vec;
×
353
    pdns::settings::rec::readYamlForwardZonesFile(filename, vec, log);
×
354
    for (const auto& forward : vec) {
×
355
      SyncRes::AuthDomain authDomain;
×
356
      authDomain.d_name = DNSName(string(forward.zone));
×
357
      authDomain.d_rdForward = forward.recurse;
×
358
      for (const auto& forwarder : forward.forwarders) {
×
359
        ComboAddress addr = pdns::fromNameOrIP(string(forwarder), 53, log);
×
360
        authDomain.d_servers.emplace_back(addr);
×
361
      }
×
362
      (*newMap)[authDomain.d_name] = authDomain;
×
363
      if (forward.notify_allowed) {
×
364
        newSet->insert(authDomain.d_name);
×
365
      }
×
366
    }
×
367
  }
×
368
  else {
×
369
    SLOG(g_log << Logger::Warning << "Reading zone forwarding information from '" << filename << "'" << endl,
×
370
         log->info(Logr::Notice, "Reading zone forwarding information", "file", Logging::Loggable(filename)));
×
371
    auto filePtr = pdns::UniqueFilePtr(fopen(filename.c_str(), "r"));
×
372
    if (!filePtr) {
×
373
      int err = errno;
×
374
      throw PDNSException("Error opening forward-zones-file '" + filename + "': " + stringerror(err));
×
375
    }
×
376

377
    string line;
×
378
    int linenum = 0;
×
379
    while (linenum++, stringfgets(filePtr.get(), line)) {
×
380
      SyncRes::AuthDomain authDomain;
×
381
      boost::trim(line);
×
382
      if (line[0] == '#') { // Comment line, skip to the next line
×
383
        continue;
×
384
      }
×
385
      string domain;
×
386
      string instructions;
×
387
      std::tie(domain, instructions) = splitField(line, '=');
×
388
      instructions = splitField(instructions, '#').first; // Remove EOL comments
×
389
      boost::trim(domain);
×
390
      boost::trim(instructions);
×
391
      if (domain.empty()) {
×
392
        if (instructions.empty()) { // empty line
×
393
          continue;
×
394
        }
×
395
        throw PDNSException("Error parsing line " + std::to_string(linenum) + " of " + filename);
×
396
      }
×
397

398
      bool allowNotifyFor = false;
×
399

400
      for (; !domain.empty(); domain.erase(0, 1)) {
×
401
        switch (domain[0]) {
×
402
        case '+':
×
403
          authDomain.d_rdForward = true;
×
404
          continue;
×
405
        case '^':
×
406
          allowNotifyFor = true;
×
407
          continue;
×
408
        }
×
409
        break;
×
410
      }
×
411

412
      if (domain.empty()) {
×
413
        throw PDNSException("Error parsing line " + std::to_string(linenum) + " of " + filename);
×
414
      }
×
415

416
      try {
×
417
        convertServersForAD(domain, instructions, authDomain, ",; ", log, false);
×
418
      }
×
419
      catch (const PDNSException& e) {
×
420
        throw PDNSException(e.reason + "on line " + std::to_string(linenum) + " of " + filename);
×
421
      }
×
422
      catch (...) {
×
423
        throw PDNSException("Conversion error parsing line " + std::to_string(linenum) + " of " + filename);
×
424
      }
×
425

426
      authDomain.d_name = DNSName(domain);
×
427
      (*newMap)[authDomain.d_name] = authDomain;
×
428
      if (allowNotifyFor) {
×
429
        newSet->insert(authDomain.d_name);
×
430
      }
×
431
    }
×
432
  }
×
433
  SLOG(g_log << Logger::Warning << "Done parsing " << newMap->size() - before
×
434
             << " forwarding instructions from file '"
×
435
             << filename << "'" << endl,
×
436
       log->info(Logr::Notice, "Done parsing forwarding instructions from file", "file",
×
437
                 Logging::Loggable(filename), "count",
×
438
                 Logging::Loggable(newMap->size() - before)));
×
439
}
×
440

441
static void processExportEtcHosts(std::shared_ptr<SyncRes::domainmap_t>& newMap, Logr::log_t log)
442
{
185✔
443
  if (!::arg().mustDo("export-etc-hosts")) {
185!
444
    return;
185✔
445
  }
185✔
446
  string fname = ::arg()["etc-hosts-file"];
×
447
  ifstream ifs(fname);
×
448
  if (!ifs) {
×
449
    SLOG(g_log << Logger::Warning << "Could not open " << fname << " for reading" << endl,
×
450
         log->error(Logr::Warning, "Could not open file for reading", "file", Logging::Loggable(fname)));
×
451
    return;
×
452
  }
×
453
  vector<string> parts;
×
454
  std::string line{};
×
455
  while (getline(ifs, line)) {
×
456
    if (!parseEtcHostsLine(parts, line)) {
×
457
      continue;
×
458
    }
×
459

460
    try {
×
461
      string searchSuffix = ::arg()["export-etc-hosts-search-suffix"];
×
462
      addForwardAndReverseLookupEntries(*newMap, searchSuffix, parts, log);
×
463
    }
×
464
    catch (const PDNSException& ex) {
×
465
      SLOG(g_log << Logger::Warning
×
466
                 << "The line `" << line << "` "
×
467
                 << "in the provided etc-hosts file `" << fname << "` "
×
468
                 << "could not be added: " << ex.reason << ". Going to skip it."
×
469
                 << endl,
×
470
           log->info(Logr::Notice, "Skipping line in etc-hosts file",
×
471
                     "line", Logging::Loggable(line),
×
472
                     "hosts-file", Logging::Loggable(fname),
×
473
                     "reason", Logging::Loggable(ex.reason)));
×
474
    }
×
475
  }
×
476
}
×
477

478
static void processServeRFC1918(std::shared_ptr<SyncRes::domainmap_t>& newMap, Logr::log_t log)
479
{
185✔
480
  if (!::arg().mustDo("serve-rfc1918")) {
185!
481
    return;
×
482
  }
×
483
  SLOG(g_log << Logger::Warning << "Inserting rfc 1918 private space zones" << endl,
185✔
484
       log->info(Logr::Notice, "Inserting rfc 1918 private space zones"));
185✔
485

486
  makePartialIPZone(*newMap, {"127"}, log);
185✔
487
  makePartialIPZone(*newMap, {"10"}, log);
185✔
488
  makePartialIPZone(*newMap, {"192", "168"}, log);
185✔
489

490
  for (int count = 16; count < 32; count++) {
3,145✔
491
    makePartialIPZone(*newMap, {"172", std::to_string(count).c_str()}, log);
2,960✔
492
  }
2,960✔
493
}
185✔
494

495
static void processServeRFC6303(std::shared_ptr<SyncRes::domainmap_t>& newMap, Logr::log_t log)
496
{
185✔
497
  if (!::arg().mustDo("serve-rfc6303")) {
185✔
498
    return;
1✔
499
  }
1✔
500
  if (!::arg().mustDo("serve-rfc1918")) {
184!
501
    return;
×
502
  }
×
503
  SLOG(g_log << Logger::Warning << "Inserting rfc 6303 private space zones" << endl,
184✔
504
       log->info(Logr::Notice, "Inserting rfc 6303 private space zones"));
184✔
505
  // Section 4.2
506
  makePartialIPZone(*newMap, {"0"}, log);
184✔
507
  // makePartialIPZone(*newMap, { "127" }, log) already done in processServeRFC1918
508
  makePartialIPZone(*newMap, {"169", "254"}, log);
184✔
509
  makePartialIPZone(*newMap, {"192", "0", "2"}, log);
184✔
510
  makePartialIPZone(*newMap, {"198", "51", "100"}, log);
184✔
511
  makePartialIPZone(*newMap, {"203", "0", "113"}, log);
184✔
512
  makePartialIPZone(*newMap, {"255", "255", "255", "255"}, log); // actually produces NODATA instead of the RFC's NXDOMAIN
184✔
513

514
  // Note v6 names are not reversed
515
  // Section 4.3
516
  // makePartialIP6Zone(*newMap, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa", log) already handled by SyncRes::doSpecialNamesResolve, in accordance with section 4.2
517
  makePartialIP6Zone(*newMap, "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa", log); // actually produces NODATA instead of the RFC's NXDOMAIN
184✔
518
  // Section 4.4
519
  makePartialIP6Zone(*newMap, "d.f.ip6.arpa", log);
184✔
520
  // Section 4.5
521
  makePartialIP6Zone(*newMap, "8.e.f.ip6.arpa", log);
184✔
522
  makePartialIP6Zone(*newMap, "9.e.f.ip6.arpa", log);
184✔
523
  makePartialIP6Zone(*newMap, "a.e.f.ip6.arpa", log);
184✔
524
  makePartialIP6Zone(*newMap, "b.e.f.ip6.arpa", log);
184✔
525
  // Section 4.6
526
  makePartialIP6Zone(*newMap, "8.b.d.0.1.0.0.2.ip6.arpa", log);
184✔
527
}
184✔
528

529
static void processAllowNotifyFor(shared_ptr<notifyset_t>& newSet)
530
{
185✔
531
  vector<string> parts;
185✔
532
  stringtok(parts, ::arg()["allow-notify-for"], " ,\t\n\r");
185✔
533
  for (auto& part : parts) {
185✔
534
    newSet->insert(DNSName(part));
13✔
535
  }
13✔
536
}
185✔
537

538
static void processAllowNotifyForFile(shared_ptr<notifyset_t>& newSet, Logr::log_t log)
539
{
185✔
540
  const auto& filename = ::arg()["allow-notify-for-file"];
185✔
541
  if (filename.empty()) {
185!
542
    return;
185✔
543
  }
185✔
544
  const uint64_t before = newSet->size();
×
545
  if (boost::ends_with(filename, ".yml")) {
×
546
    ::rust::Vec<::rust::String> vec;
×
547
    pdns::settings::rec::readYamlAllowNotifyForFile(filename, vec, log);
×
548
    for (const auto& name : vec) {
×
549
      newSet->insert(DNSName(string(name)));
×
550
    }
×
551
  }
×
552
  else {
×
553
    SLOG(g_log << Logger::Warning << "Reading NOTIFY-allowed zones from '" << filename << "'" << endl,
×
554
         log->info(Logr::Notice, "Reading NOTIFY-allowed zones from file", "file", Logging::Loggable(filename)));
×
555
    auto filePtr = pdns::UniqueFilePtr(fopen(filename.c_str(), "r"));
×
556
    if (!filePtr) {
×
557
      throw PDNSException("Error opening allow-notify-for-file '" + filename + "': " + stringerror());
×
558
    }
×
559

560
    string line;
×
561
    while (stringfgets(filePtr.get(), line)) {
×
562
      boost::trim(line);
×
563
      if (line[0] == '#') { // Comment line, skip to the next line
×
564
        continue;
×
565
      }
×
566
      newSet->insert(DNSName(line));
×
567
    }
×
568
  }
×
569
  SLOG(g_log << Logger::Warning << "Done parsing " << newSet->size() - before << " NOTIFY-allowed zones from file '" << filename << "'" << endl,
×
570
       log->info(Logr::Notice, "Done parsing NOTIFY-allowed zones from file", "file", Logging::Loggable(filename), "count", Logging::Loggable(newSet->size() - before)));
×
571
}
×
572

573
std::tuple<std::shared_ptr<SyncRes::domainmap_t>, std::shared_ptr<notifyset_t>> parseZoneConfiguration(bool yaml)
574
{
185✔
575
  auto log = g_slog->withName("config");
185✔
576

577
  auto newMap = std::make_shared<SyncRes::domainmap_t>();
185✔
578
  auto newSet = std::make_shared<notifyset_t>();
185✔
579

580
  processForwardZones(newMap, log);
185✔
581
  processForwardZonesFile(newMap, newSet, log);
185✔
582
  if (yaml) {
185✔
583
    auto lci = g_luaconfs.getLocal();
17✔
584
    processApiZonesFile("apizones", newMap, newSet, log);
17✔
585
    for (const auto& catz : lci->catalogzones) {
17✔
586
      processApiZonesFile("catzone." + catz.d_catz->getName().toString(), newMap, newSet, log);
11✔
587
    }
11✔
588
  }
17✔
589
  processExportEtcHosts(newMap, log);
185✔
590
  processServeRFC1918(newMap, log);
185✔
591
  processServeRFC6303(newMap, log);
185✔
592
  processAllowNotifyFor(newSet);
185✔
593
  processAllowNotifyForFile(newSet, log);
185✔
594

595
  return {newMap, newSet};
185✔
596
}
185✔
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