]>
Commit | Line | Data |
---|---|---|
49a699c4 | 1 | /* |
6edbf68a PL |
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 | */ | |
84d4747e | 22 | |
870a0fe4 AT |
23 | #ifdef HAVE_CONFIG_H |
24 | #include "config.h" | |
25 | #endif | |
84d4747e | 26 | |
9883d3f9 OM |
27 | #include <sys/stat.h> |
28 | ||
23855ca0 | 29 | #include "reczones-helpers.hh" |
49a699c4 | 30 | #include "arguments.hh" |
49a699c4 | 31 | #include "dnsrecords.hh" |
c6d82407 OM |
32 | #include "logger.hh" |
33 | #include "syncres.hh" | |
34 | #include "zoneparser-tng.hh" | |
9883d3f9 | 35 | #include "settings/cxxsettings.hh" |
302df819 AT |
36 | |
37 | extern int g_argc; | |
38 | extern char** g_argv; | |
49a699c4 | 39 | |
5c7e7d48 OM |
40 | bool primeHints(time_t now) |
41 | { | |
42 | const string hintfile = ::arg()["hint-file"]; | |
43 | vector<DNSRecord> nsvec; | |
44 | bool ret = true; | |
3e5afd94 | 45 | |
0908f757 | 46 | if (hintfile == "no" || hintfile == "no-refresh") { |
5c7e7d48 | 47 | auto log = g_slog->withName("config"); |
0908f757 OM |
48 | SLOG(g_log << Logger::Debug << "Priming root disabled by hint-file setting" << endl, |
49 | log->info(Logr::Debug, "Priming root disabled by hint-file setting")); | |
5c7e7d48 OM |
50 | return ret; |
51 | } | |
52 | ||
53 | if (hintfile.empty()) { | |
54 | putDefaultHintsIntoCache(now, nsvec); | |
55 | } | |
56 | else { | |
57 | ret = readHintsIntoCache(now, hintfile, nsvec); | |
49a699c4 | 58 | } |
7d021373 | 59 | |
ccfadb6c | 60 | g_recCache->doWipeCache(g_rootdnsname, false, QType::NS); |
5c7e7d48 OM |
61 | 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 |
62 | return ret; | |
1b4e0ae0 OM |
63 | } |
64 | ||
199e75c7 | 65 | static void convertServersForAD(const std::string& zone, const std::string& input, SyncRes::AuthDomain& authDomain, const char* sepa, Logr::log_t log, bool verbose = true) |
49a699c4 BH |
66 | { |
67 | vector<string> servers; | |
68 | stringtok(servers, input, sepa); | |
199e75c7 | 69 | authDomain.d_servers.clear(); |
49a699c4 | 70 | |
d8d1d955 | 71 | vector<string> addresses; |
199e75c7 OM |
72 | for (auto& server : servers) { |
73 | ComboAddress addr = parseIPAndPort(server, 53); | |
74 | authDomain.d_servers.push_back(addr); | |
d8d1d955 OM |
75 | if (verbose) { |
76 | addresses.push_back(addr.toStringWithPort()); | |
77 | } | |
78 | } | |
79 | if (verbose) { | |
80 | if (!g_slogStructured) { | |
81 | g_log << Logger::Info << "Redirecting queries for zone '" << zone << "' "; | |
199e75c7 | 82 | if (authDomain.d_rdForward) { |
d8d1d955 OM |
83 | g_log << "with recursion "; |
84 | } | |
85 | g_log << "to: "; | |
86 | bool first = true; | |
199e75c7 | 87 | for (const auto& address : addresses) { |
6cb5db59 | 88 | if (!first) { |
d8d1d955 | 89 | g_log << ", "; |
6cb5db59 OM |
90 | } |
91 | else { | |
d8d1d955 OM |
92 | first = false; |
93 | } | |
199e75c7 | 94 | g_log << address; |
d8d1d955 OM |
95 | } |
96 | g_log << endl; | |
97 | } | |
98 | else { | |
199e75c7 | 99 | log->info(Logr::Info, "Redirecting queries", "zone", Logging::Loggable(zone), "recursion", Logging::Loggable(authDomain.d_rdForward), "addresses", Logging::IterLoggable(addresses.begin(), addresses.end())); |
d8d1d955 | 100 | } |
49a699c4 | 101 | } |
49a699c4 BH |
102 | } |
103 | ||
050e6877 | 104 | static void* pleaseUseNewSDomainsMap(std::shared_ptr<SyncRes::domainmap_t> newmap) |
49a699c4 | 105 | { |
645b217b | 106 | SyncRes::setDomainMap(std::move(newmap)); |
199e75c7 | 107 | return nullptr; |
49a699c4 BH |
108 | } |
109 | ||
9883d3f9 | 110 | string reloadZoneConfiguration(bool yaml) |
49a699c4 | 111 | { |
fa9fb323 | 112 | std::shared_ptr<SyncRes::domainmap_t> original = SyncRes::getDomainMap(); |
d8d1d955 | 113 | auto log = g_slog->withName("config"); |
6cb5db59 | 114 | |
9883d3f9 OM |
115 | string configname = ::arg()["config-dir"] + "/recursor"; |
116 | if (!::arg()["config-name"].empty()) { | |
117 | configname = ::arg()["config-dir"] + "/recursor-" + ::arg()["config-name"]; | |
118 | } | |
119 | cleanSlashes(configname); | |
120 | ||
49a699c4 | 121 | try { |
d8d1d955 | 122 | SLOG(g_log << Logger::Warning << "Reloading zones, purging data from cache" << endl, |
d197c31c | 123 | log->info(Logr::Notice, "Reloading zones, purging data from cache")); |
a712cb56 | 124 | |
9883d3f9 OM |
125 | if (yaml) { |
126 | configname += ".yml"; | |
127 | string msg; | |
128 | pdns::rust::settings::rec::Recursorsettings settings; | |
129 | // XXX Does ::arg()["include-dir"] have the right value, i.e. potentially overriden by command line? | |
130 | auto yamlstatus = pdns::settings::rec::readYamlSettings(configname, ::arg()["include-dir"], settings, msg, log); | |
131 | ||
132 | switch (yamlstatus) { | |
133 | case pdns::settings::rec::YamlSettingsStatus::CannotOpen: | |
134 | throw runtime_error("Unable to open '" + configname + "': " + msg); | |
135 | break; | |
136 | case pdns::settings::rec::YamlSettingsStatus::PresentButFailed: | |
137 | throw runtime_error("Error processing '" + configname + "': " + msg); | |
138 | break; | |
139 | case pdns::settings::rec::YamlSettingsStatus::OK: | |
140 | // Does *not* set include-dir | |
141 | pdns::settings::rec::setArgsForZoneRelatedSettings(settings); | |
142 | break; | |
143 | } | |
302df819 | 144 | } |
9883d3f9 OM |
145 | else { |
146 | configname += ".conf"; | |
49a699c4 | 147 | |
9883d3f9 OM |
148 | if (!::arg().preParseFile(configname, "forward-zones")) { |
149 | throw runtime_error("Unable to re-parse configuration file '" + configname + "'"); | |
150 | } | |
151 | ::arg().preParseFile(configname, "forward-zones-file"); | |
152 | ::arg().preParseFile(configname, "forward-zones-recurse"); | |
153 | ::arg().preParseFile(configname, "auth-zones"); | |
154 | ::arg().preParseFile(configname, "allow-notify-for"); | |
155 | ::arg().preParseFile(configname, "allow-notify-for-file"); | |
156 | ::arg().preParseFile(configname, "export-etc-hosts", "off"); | |
157 | ::arg().preParseFile(configname, "serve-rfc1918"); | |
158 | ::arg().preParseFile(configname, "include-dir"); | |
159 | ::arg().preParse(g_argc, g_argv, "include-dir"); | |
160 | ||
161 | // then process includes | |
162 | std::vector<std::string> extraConfigs; | |
163 | ::arg().gatherIncludes(::arg()["include-dir"], ".conf", extraConfigs); | |
164 | ||
165 | for (const std::string& filename : extraConfigs) { | |
166 | if (!::arg().preParseFile(filename, "forward-zones", ::arg()["forward-zones"])) { | |
167 | throw runtime_error("Unable to re-parse configuration file include '" + filename + "'"); | |
168 | } | |
169 | ::arg().preParseFile(filename, "forward-zones-file", ::arg()["forward-zones-file"]); | |
170 | ::arg().preParseFile(filename, "forward-zones-recurse", ::arg()["forward-zones-recurse"]); | |
171 | ::arg().preParseFile(filename, "auth-zones", ::arg()["auth-zones"]); | |
172 | ::arg().preParseFile(filename, "allow-notify-for", ::arg()["allow-notify-for"]); | |
173 | ::arg().preParseFile(filename, "allow-notify-for-file", ::arg()["allow-notify-for-file"]); | |
174 | ::arg().preParseFile(filename, "export-etc-hosts", ::arg()["export-etc-hosts"]); | |
175 | ::arg().preParseFile(filename, "serve-rfc1918", ::arg()["serve-rfc1918"]); | |
176 | } | |
177 | } | |
178 | // Process command line args potentially overriding what we read from config files | |
452d5116 AT |
179 | ::arg().preParse(g_argc, g_argv, "forward-zones"); |
180 | ::arg().preParse(g_argc, g_argv, "forward-zones-file"); | |
4b6d1ba4 | 181 | ::arg().preParse(g_argc, g_argv, "forward-zones-recurse"); |
452d5116 | 182 | ::arg().preParse(g_argc, g_argv, "auth-zones"); |
35189b7d KF |
183 | ::arg().preParse(g_argc, g_argv, "allow-notify-for"); |
184 | ::arg().preParse(g_argc, g_argv, "allow-notify-for-file"); | |
452d5116 AT |
185 | ::arg().preParse(g_argc, g_argv, "export-etc-hosts"); |
186 | ::arg().preParse(g_argc, g_argv, "serve-rfc1918"); | |
187 | ||
9883d3f9 | 188 | auto [newDomainMap, newNotifySet] = parseZoneConfiguration(yaml); |
b68af3ee | 189 | |
190 | // purge both original and new names | |
191 | std::set<DNSName> oldAndNewDomains; | |
9883d3f9 OM |
192 | for (const auto& entry : *newDomainMap) { |
193 | oldAndNewDomains.insert(entry.first); | |
b68af3ee | 194 | } |
195 | ||
fa9fb323 | 196 | if (original) { |
9883d3f9 OM |
197 | for (const auto& entry : *original) { |
198 | oldAndNewDomains.insert(entry.first); | |
b68af3ee | 199 | } |
200 | } | |
201 | ||
35189b7d KF |
202 | // these explicitly-named captures should not be necessary, as lambda |
203 | // capture of tuple-like structured bindings is permitted, but some | |
204 | // compilers still don't allow it | |
9883d3f9 OM |
205 | broadcastFunction([dmap = newDomainMap] { return pleaseUseNewSDomainsMap(dmap); }); |
206 | broadcastFunction([nsset = newNotifySet] { return pleaseSupplantAllowNotifyFor(nsset); }); | |
79911452 OM |
207 | |
208 | // Wipe the caches *after* the new auth domain info has been set | |
209 | // up, as a query during setting up might fill the caches | |
210 | // again. Old code did the clear before, exposing a race. | |
9883d3f9 OM |
211 | for (const auto& entry : oldAndNewDomains) { |
212 | wipeCaches(entry, true, 0xffff); | |
79911452 | 213 | } |
49a699c4 BH |
214 | return "ok\n"; |
215 | } | |
d8d1d955 OM |
216 | catch (const std::exception& e) { |
217 | SLOG(g_log << Logger::Error << "Encountered error reloading zones, keeping original data: " << e.what() << endl, | |
218 | log->error(Logr::Error, e.what(), "Encountered error reloading zones, keeping original data")); | |
49a699c4 | 219 | } |
d8d1d955 OM |
220 | catch (const PDNSException& ae) { |
221 | SLOG(g_log << Logger::Error << "Encountered error reloading zones, keeping original data: " << ae.reason << endl, | |
222 | log->error(Logr::Error, ae.reason, "Encountered error reloading zones, keeping original data")); | |
49a699c4 | 223 | } |
fa9fb323 | 224 | catch (...) { |
d8d1d955 | 225 | SLOG(g_log << Logger::Error << "Encountered unknown error reloading zones, keeping original data" << endl, |
6cb5db59 | 226 | log->error(Logr::Error, "Exception", "Encountered error reloading zones, keeping original data")); |
49a699c4 BH |
227 | } |
228 | return "reloading failed, see log\n"; | |
229 | } | |
230 | ||
9883d3f9 | 231 | static void readAuthZoneData(SyncRes::AuthDomain& authDomain, const pair<string, string>& headers, Logr::log_t log) |
49a699c4 | 232 | { |
9883d3f9 OM |
233 | SLOG(g_log << Logger::Notice << "Parsing authoritative data for zone '" << headers.first << "' from file '" << headers.second << "'" << endl, |
234 | log->info(Logr::Notice, "Parsing authoritative data from file", "zone", Logging::Loggable(headers.first), "file", Logging::Loggable(headers.second))); | |
235 | ZoneParserTNG zpt(headers.second, DNSName(headers.first)); | |
236 | zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps")); | |
237 | zpt.setMaxIncludes(::arg().asNum("max-include-depth")); | |
238 | DNSResourceRecord resourceRecord; | |
239 | DNSRecord dnsrecord; | |
240 | while (zpt.get(resourceRecord)) { | |
241 | try { | |
242 | dnsrecord = DNSRecord(resourceRecord); | |
243 | dnsrecord.d_place = DNSResourceRecord::ANSWER; | |
244 | } | |
245 | catch (std::exception& e) { | |
246 | throw PDNSException("Error parsing record '" + resourceRecord.qname.toLogString() + "' of type " + resourceRecord.qtype.toString() + " in zone '" + headers.first + "' from file '" + headers.second + "': " + e.what()); | |
247 | } | |
248 | catch (...) { | |
249 | throw PDNSException("Error parsing record '" + resourceRecord.qname.toLogString() + "' of type " + resourceRecord.qtype.toString() + " in zone '" + headers.first + "' from file '" + headers.second + "'"); | |
250 | } | |
49a699c4 | 251 | |
9883d3f9 OM |
252 | authDomain.d_records.insert(dnsrecord); |
253 | } | |
254 | } | |
49a699c4 | 255 | |
9883d3f9 OM |
256 | static void processForwardZones(shared_ptr<SyncRes::domainmap_t>& newMap, Logr::log_t log) |
257 | { | |
258 | const std::array<string, 3> option_names = {"auth-zones", "forward-zones", "forward-zones-recurse"}; | |
259 | ||
260 | for (size_t option = 0; option < option_names.size(); ++option) { | |
261 | vector<string> parts; | |
262 | stringtok(parts, ::arg()[option_names.at(option)], " ,\t\n\r"); | |
263 | for (const auto& part : parts) { | |
264 | SyncRes::AuthDomain authDomain; | |
265 | if (part.find('=') == string::npos) { | |
266 | throw PDNSException("Error parsing '" + part + "', missing ="); | |
267 | } | |
268 | pair<string, string> headers = splitField(part, '='); | |
dc593046 OM |
269 | boost::trim(headers.first); |
270 | boost::trim(headers.second); | |
9883d3f9 OM |
271 | |
272 | if (option == 0) { | |
273 | authDomain.d_rdForward = false; | |
274 | readAuthZoneData(authDomain, headers, log); | |
49a699c4 BH |
275 | } |
276 | else { | |
9883d3f9 OM |
277 | authDomain.d_rdForward = (option == 2); |
278 | convertServersForAD(headers.first, headers.second, authDomain, ";", log); | |
49a699c4 | 279 | } |
3337c2f7 | 280 | |
9883d3f9 OM |
281 | authDomain.d_name = DNSName(headers.first); |
282 | (*newMap)[authDomain.d_name] = authDomain; | |
49a699c4 BH |
283 | } |
284 | } | |
9883d3f9 OM |
285 | } |
286 | ||
287 | static void processApiZonesFile(shared_ptr<SyncRes::domainmap_t>& newMap, shared_ptr<notifyset_t>& newSet, Logr::log_t log) | |
288 | { | |
289 | if (::arg()["api-config-dir"].empty()) { | |
290 | return; | |
291 | } | |
292 | const auto filename = ::arg()["api-config-dir"] + "/apizones"; | |
293 | struct stat statStruct | |
294 | { | |
295 | }; | |
296 | // It's a TOCTU, but a harmless one | |
297 | if (stat(filename.c_str(), &statStruct) != 0) { | |
298 | return; | |
299 | } | |
300 | ||
301 | SLOG(g_log << Logger::Notice << "Processing ApiZones YAML settings from " << filename << endl, | |
302 | log->info(Logr::Notice, "Processing ApiZones YAML settings", "path", Logging::Loggable(filename))); | |
303 | ||
304 | const uint64_t before = newMap->size(); | |
fa9fb323 | 305 | |
9883d3f9 OM |
306 | std::unique_ptr<pdns::rust::settings::rec::ApiZones> zones = pdns::rust::settings::rec::api_read_zones(filename); |
307 | zones->validate("apizones"); | |
308 | ||
309 | for (const auto& forward : zones->forward_zones) { | |
310 | SyncRes::AuthDomain authDomain; | |
311 | authDomain.d_name = DNSName(string(forward.zone)); | |
312 | authDomain.d_rdForward = forward.recurse; | |
313 | for (const auto& forwarder : forward.forwarders) { | |
314 | ComboAddress addr = parseIPAndPort(string(forwarder), 53); | |
315 | authDomain.d_servers.emplace_back(addr); | |
316 | } | |
317 | (*newMap)[authDomain.d_name] = authDomain; | |
318 | if (forward.notify_allowed) { | |
319 | newSet->insert(authDomain.d_name); | |
320 | } | |
321 | } | |
322 | for (const auto& auth : zones->auth_zones) { | |
323 | SyncRes::AuthDomain authDomain; | |
324 | authDomain.d_name = DNSName(string(auth.zone)); | |
325 | readAuthZoneData(authDomain, {string(auth.zone), string(auth.file)}, log); | |
326 | (*newMap)[authDomain.d_name] = authDomain; | |
327 | } | |
328 | SLOG(g_log << Logger::Warning << "Done parsing " << newMap->size() - before | |
329 | << " ApiZones YAML settings from file '" | |
330 | << filename << "'" << endl, | |
331 | log->info(Logr::Notice, "Done parsing ApiZones YAML from file", "file", | |
332 | Logging::Loggable(filename), "count", | |
333 | Logging::Loggable(newMap->size() - before))); | |
334 | } | |
335 | ||
336 | static void processForwardZonesFile(shared_ptr<SyncRes::domainmap_t>& newMap, shared_ptr<notifyset_t>& newSet, Logr::log_t log) | |
337 | { | |
17417d54 | 338 | const auto& filename = ::arg()["forward-zones-file"]; |
9883d3f9 OM |
339 | if (filename.empty()) { |
340 | return; | |
341 | } | |
342 | const uint64_t before = newMap->size(); | |
343 | ||
344 | if (boost::ends_with(filename, ".yml")) { | |
345 | ::rust::Vec<pdns::rust::settings::rec::ForwardZone> vec; | |
346 | pdns::settings::rec::readYamlForwardZonesFile(filename, vec, log); | |
347 | for (const auto& forward : vec) { | |
348 | SyncRes::AuthDomain authDomain; | |
349 | authDomain.d_name = DNSName(string(forward.zone)); | |
350 | authDomain.d_rdForward = forward.recurse; | |
351 | for (const auto& forwarder : forward.forwarders) { | |
352 | ComboAddress addr = parseIPAndPort(string(forwarder), 53); | |
353 | authDomain.d_servers.emplace_back(addr); | |
354 | } | |
355 | (*newMap)[authDomain.d_name] = authDomain; | |
356 | if (forward.notify_allowed) { | |
357 | newSet->insert(authDomain.d_name); | |
358 | } | |
359 | } | |
360 | } | |
361 | else { | |
362 | SLOG(g_log << Logger::Warning << "Reading zone forwarding information from '" << filename << "'" << endl, | |
363 | log->info(Logr::Notice, "Reading zone forwarding information", "file", Logging::Loggable(filename))); | |
01807c64 | 364 | auto filePtr = pdns::UniqueFilePtr(fopen(filename.c_str(), "r")); |
9883d3f9 OM |
365 | if (!filePtr) { |
366 | int err = errno; | |
367 | throw PDNSException("Error opening forward-zones-file '" + filename + "': " + stringerror(err)); | |
49a699c4 BH |
368 | } |
369 | ||
834942f1 | 370 | string line; |
fa9fb323 | 371 | int linenum = 0; |
9883d3f9 OM |
372 | while (linenum++, stringfgets(filePtr.get(), line)) { |
373 | SyncRes::AuthDomain authDomain; | |
dc593046 | 374 | boost::trim(line); |
f904c51c | 375 | if (line[0] == '#') { // Comment line, skip to the next line |
fa2909dc | 376 | continue; |
f904c51c FM |
377 | } |
378 | string domain; | |
379 | string instructions; | |
1a09e47b | 380 | std::tie(domain, instructions) = splitField(line, '='); |
fa2909dc | 381 | instructions = splitField(instructions, '#').first; // Remove EOL comments |
dc593046 OM |
382 | boost::trim(domain); |
383 | boost::trim(instructions); | |
35189b7d KF |
384 | if (domain.empty()) { |
385 | if (instructions.empty()) { // empty line | |
386 | continue; | |
387 | } | |
9883d3f9 | 388 | throw PDNSException("Error parsing line " + std::to_string(linenum) + " of " + filename); |
e58483cc | 389 | } |
35189b7d KF |
390 | |
391 | bool allowNotifyFor = false; | |
392 | ||
393 | for (; !domain.empty(); domain.erase(0, 1)) { | |
394 | switch (domain[0]) { | |
395 | case '+': | |
9883d3f9 | 396 | authDomain.d_rdForward = true; |
35189b7d KF |
397 | continue; |
398 | case '^': | |
399 | allowNotifyFor = true; | |
400 | continue; | |
401 | } | |
402 | break; | |
49a699c4 | 403 | } |
35189b7d | 404 | |
fa9fb323 | 405 | if (domain.empty()) { |
9883d3f9 | 406 | throw PDNSException("Error parsing line " + std::to_string(linenum) + " of " + filename); |
49a699c4 BH |
407 | } |
408 | ||
409 | try { | |
9883d3f9 | 410 | convertServersForAD(domain, instructions, authDomain, ",; ", log, false); |
49a699c4 | 411 | } |
fa9fb323 | 412 | catch (...) { |
9883d3f9 | 413 | throw PDNSException("Conversion error parsing line " + std::to_string(linenum) + " of " + filename); |
49a699c4 BH |
414 | } |
415 | ||
9883d3f9 OM |
416 | authDomain.d_name = DNSName(domain); |
417 | (*newMap)[authDomain.d_name] = authDomain; | |
35189b7d | 418 | if (allowNotifyFor) { |
9883d3f9 | 419 | newSet->insert(authDomain.d_name); |
35189b7d | 420 | } |
49a699c4 | 421 | } |
49a699c4 | 422 | } |
9883d3f9 OM |
423 | SLOG(g_log << Logger::Warning << "Done parsing " << newMap->size() - before |
424 | << " forwarding instructions from file '" | |
425 | << filename << "'" << endl, | |
426 | log->info(Logr::Notice, "Done parsing forwarding instructions from file", "file", | |
427 | Logging::Loggable(filename), "count", | |
428 | Logging::Loggable(newMap->size() - before))); | |
429 | } | |
49a699c4 | 430 | |
9883d3f9 OM |
431 | static void processExportEtcHosts(std::shared_ptr<SyncRes::domainmap_t>& newMap, Logr::log_t log) |
432 | { | |
433 | if (!::arg().mustDo("export-etc-hosts")) { | |
434 | return; | |
435 | } | |
436 | string fname = ::arg()["etc-hosts-file"]; | |
437 | ifstream ifs(fname); | |
438 | if (!ifs) { | |
439 | SLOG(g_log << Logger::Warning << "Could not open " << fname << " for reading" << endl, | |
440 | log->error(Logr::Warning, "Could not open file for reading", "file", Logging::Loggable(fname))); | |
441 | return; | |
442 | } | |
443 | vector<string> parts; | |
444 | std::string line{}; | |
445 | while (getline(ifs, line)) { | |
446 | if (!parseEtcHostsLine(parts, line)) { | |
447 | continue; | |
49a699c4 | 448 | } |
fa9fb323 | 449 | |
9883d3f9 OM |
450 | try { |
451 | string searchSuffix = ::arg()["export-etc-hosts-search-suffix"]; | |
452 | addForwardAndReverseLookupEntries(*newMap, searchSuffix, parts, log); | |
453 | } | |
454 | catch (const PDNSException& ex) { | |
455 | SLOG(g_log << Logger::Warning | |
456 | << "The line `" << line << "` " | |
457 | << "in the provided etc-hosts file `" << fname << "` " | |
458 | << "could not be added: " << ex.reason << ". Going to skip it." | |
459 | << endl, | |
460 | log->info(Logr::Notice, "Skipping line in etc-hosts file", | |
461 | "line", Logging::Loggable(line), | |
462 | "hosts-file", Logging::Loggable(fname), | |
463 | "reason", Logging::Loggable(ex.reason))); | |
49a699c4 BH |
464 | } |
465 | } | |
9883d3f9 | 466 | } |
35189b7d | 467 | |
9883d3f9 OM |
468 | static void processServeRFC1918(std::shared_ptr<SyncRes::domainmap_t>& newMap, Logr::log_t log) |
469 | { | |
470 | if (!::arg().mustDo("serve-rfc1918")) { | |
471 | return; | |
472 | } | |
473 | SLOG(g_log << Logger::Warning << "Inserting rfc 1918 private space zones" << endl, | |
474 | log->info(Logr::Notice, "Inserting rfc 1918 private space zones")); | |
49a699c4 | 475 | |
9883d3f9 OM |
476 | makePartialIPZone(*newMap, {"127"}, log); |
477 | makePartialIPZone(*newMap, {"10"}, log); | |
478 | makePartialIPZone(*newMap, {"192", "168"}, log); | |
9452c5e6 | 479 | |
9883d3f9 OM |
480 | for (int count = 16; count < 32; count++) { |
481 | makePartialIPZone(*newMap, {"172", std::to_string(count).c_str()}, log); | |
49a699c4 | 482 | } |
9883d3f9 | 483 | } |
35189b7d | 484 | |
9883d3f9 OM |
485 | static void processAllowNotifyFor(shared_ptr<notifyset_t>& newSet) |
486 | { | |
487 | vector<string> parts; | |
35189b7d | 488 | stringtok(parts, ::arg()["allow-notify-for"], " ,\t\n\r"); |
84d4747e FM |
489 | for (auto& part : parts) { |
490 | newSet->insert(DNSName(part)); | |
35189b7d | 491 | } |
9883d3f9 | 492 | } |
35189b7d | 493 | |
9883d3f9 OM |
494 | static void processAllowNotifyForFile(shared_ptr<notifyset_t>& newSet, Logr::log_t log) |
495 | { | |
17417d54 | 496 | const auto& filename = ::arg()["allow-notify-for-file"]; |
9883d3f9 OM |
497 | if (filename.empty()) { |
498 | return; | |
499 | } | |
500 | const uint64_t before = newSet->size(); | |
501 | if (boost::ends_with(filename, ".yml")) { | |
502 | ::rust::Vec<::rust::String> vec; | |
503 | pdns::settings::rec::readYamlAllowNotifyForFile(filename, vec, log); | |
504 | for (const auto& name : vec) { | |
505 | newSet->insert(DNSName(string(name))); | |
506 | } | |
507 | } | |
508 | else { | |
509 | SLOG(g_log << Logger::Warning << "Reading NOTIFY-allowed zones from '" << filename << "'" << endl, | |
510 | log->info(Logr::Notice, "Reading NOTIFY-allowed zones from file", "file", Logging::Loggable(filename))); | |
01807c64 | 511 | auto filePtr = pdns::UniqueFilePtr(fopen(filename.c_str(), "r")); |
9883d3f9 OM |
512 | if (!filePtr) { |
513 | throw PDNSException("Error opening allow-notify-for-file '" + filename + "': " + stringerror()); | |
35189b7d KF |
514 | } |
515 | ||
516 | string line; | |
9883d3f9 | 517 | while (stringfgets(filePtr.get(), line)) { |
35189b7d | 518 | boost::trim(line); |
9883d3f9 | 519 | if (line[0] == '#') { // Comment line, skip to the next line |
35189b7d | 520 | continue; |
9883d3f9 | 521 | } |
35189b7d KF |
522 | newSet->insert(DNSName(line)); |
523 | } | |
35189b7d | 524 | } |
9883d3f9 OM |
525 | SLOG(g_log << Logger::Warning << "Done parsing " << newSet->size() - before << " NOTIFY-allowed zones from file '" << filename << "'" << endl, |
526 | log->info(Logr::Notice, "Done parsing NOTIFY-allowed zones from file", "file", Logging::Loggable(filename), "count", Logging::Loggable(newSet->size() - before))); | |
527 | } | |
528 | ||
529 | std::tuple<std::shared_ptr<SyncRes::domainmap_t>, std::shared_ptr<notifyset_t>> parseZoneConfiguration(bool yaml) | |
530 | { | |
531 | auto log = g_slog->withName("config"); | |
532 | ||
533 | TXTRecordContent::report(); | |
534 | OPTRecordContent::report(); | |
535 | ||
536 | auto newMap = std::make_shared<SyncRes::domainmap_t>(); | |
537 | auto newSet = std::make_shared<notifyset_t>(); | |
538 | ||
539 | processForwardZones(newMap, log); | |
540 | processForwardZonesFile(newMap, newSet, log); | |
541 | if (yaml) { | |
542 | processApiZonesFile(newMap, newSet, log); | |
543 | } | |
544 | processExportEtcHosts(newMap, log); | |
545 | processServeRFC1918(newMap, log); | |
546 | processAllowNotifyFor(newSet); | |
547 | processAllowNotifyForFile(newSet, log); | |
35189b7d KF |
548 | |
549 | return {newMap, newSet}; | |
49a699c4 | 550 | } |