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

PowerDNS / pdns / 12595591960

03 Jan 2025 09:27AM UTC coverage: 62.774% (+2.5%) from 60.245%
12595591960

Pull #15008

github

web-flow
Merge c2a2749d3 into 788f396a7
Pull Request #15008: Do not follow CNAME records for ANY or CNAME queries

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

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

50.84
/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 "settings/cxxsettings.hh"
36
#include "rec-system-resolve.hh"
37

38
// XXX consider including rec-main.hh?
39
extern int g_argc;
40
extern char** g_argv;
41
extern string g_yamlSettingsSuffix;
42

43
bool primeHints(time_t now)
44
{
300✔
45
  const string hintfile = ::arg()["hint-file"];
300✔
46
  vector<DNSRecord> nsvec;
300✔
47
  bool ret = true;
300✔
48

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

56
  if (hintfile.empty()) {
300✔
57
    putDefaultHintsIntoCache(now, nsvec);
22✔
58
  }
22✔
59
  else {
278✔
60
    ret = readHintsIntoCache(now, hintfile, nsvec);
278✔
61
  }
278✔
62

63
  g_recCache->doWipeCache(g_rootdnsname, false, QType::NS);
300✔
64
  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
300✔
65
  return ret;
300✔
66
}
300✔
67

68
static void convertServersForAD(const std::string& zone, const std::string& input, SyncRes::AuthDomain& authDomain, const char* sepa, Logr::log_t log, bool verbose = true)
69
{
31✔
70
  vector<string> servers;
31✔
71
  stringtok(servers, input, sepa);
31✔
72
  authDomain.d_servers.clear();
31✔
73

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

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

113
string reloadZoneConfiguration(bool yaml)
114
{
21✔
115
  std::shared_ptr<SyncRes::domainmap_t> original = SyncRes::getDomainMap();
21✔
116
  auto log = g_slog->withName("config");
21✔
117

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

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

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

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

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

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

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

194
    auto [newDomainMap, newNotifySet] = parseZoneConfiguration(yaml);
21✔
195

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

202
    if (original) {
21✔
203
      for (const auto& entry : *original) {
718✔
204
        oldAndNewDomains.insert(entry.first);
718✔
205
      }
718✔
206
    }
20✔
207

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

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

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

258
    authDomain.d_records.insert(dnsrecord);
242,421✔
259
  }
242,421✔
260
}
91✔
261

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

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

278
      if (option == 0) {
87✔
279
        authDomain.d_rdForward = false;
56✔
280
        readAuthZoneData(authDomain, headers, log);
56✔
281
      }
56✔
282
      else {
31✔
283
        authDomain.d_rdForward = (option == 2);
31✔
284
        convertServersForAD(headers.first, headers.second, authDomain, ";", log);
31✔
285
      }
31✔
286

287
      authDomain.d_name = DNSName(headers.first);
87✔
288
      (*newMap)[authDomain.d_name] = authDomain;
87✔
289
    }
87✔
290
  }
522✔
291
}
174✔
292

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

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

310
  const uint64_t before = newMap->size();
34✔
311

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

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

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

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

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

397
      bool allowNotifyFor = false;
×
398

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

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

415
      try {
×
416
        convertServersForAD(domain, instructions, authDomain, ",; ", log, false);
×
417
      }
×
418
      catch (...) {
×
419
        throw PDNSException("Conversion error parsing line " + std::to_string(linenum) + " of " + filename);
×
420
      }
×
421

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

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

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

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

482
  makePartialIPZone(*newMap, {"127"}, log);
174✔
483
  makePartialIPZone(*newMap, {"10"}, log);
174✔
484
  makePartialIPZone(*newMap, {"192", "168"}, log);
174✔
485

486
  for (int count = 16; count < 32; count++) {
2,958✔
487
    makePartialIPZone(*newMap, {"172", std::to_string(count).c_str()}, log);
2,784✔
488
  }
2,784✔
489
}
174✔
490

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

510
  // Note v6 names are not reversed
511
  // Section 4.3
512
  // 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
513
  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
173✔
514
  // Section 4.4
515
  makePartialIP6Zone(*newMap, "d.f.ip6.arpa", log);
173✔
516
  // Section 4.5
517
  makePartialIP6Zone(*newMap, "8.e.f.ip6.arpa", log);
173✔
518
  makePartialIP6Zone(*newMap, "9.e.f.ip6.arpa", log);
173✔
519
  makePartialIP6Zone(*newMap, "a.e.f.ip6.arpa", log);
173✔
520
  makePartialIP6Zone(*newMap, "b.e.f.ip6.arpa", log);
173✔
521
  // Section 4.6
522
  makePartialIP6Zone(*newMap, "8.b.d.0.1.0.0.2.ip6.arpa", log);
173✔
523
}
173✔
524

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

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

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

569
std::tuple<std::shared_ptr<SyncRes::domainmap_t>, std::shared_ptr<notifyset_t>> parseZoneConfiguration(bool yaml)
570
{
174✔
571
  auto log = g_slog->withName("config");
174✔
572

573
  auto newMap = std::make_shared<SyncRes::domainmap_t>();
174✔
574
  auto newSet = std::make_shared<notifyset_t>();
174✔
575

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

591
  return {newMap, newSet};
174✔
592
}
174✔
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