]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recursordist/rec-lua-conf.cc
Merge pull request #13387 from omoerbeek/rec-b-root-servers
[thirdparty/pdns.git] / pdns / recursordist / rec-lua-conf.cc
CommitLineData
6a99b9a4 1#include "config.h"
3e61e7f7 2#include "ext/luawrapper/include/LuaContext.hpp"
6a99b9a4 3
3e61e7f7 4#include <fstream>
ad42489c 5#include <thread>
3e61e7f7 6#include "namespaces.hh"
7#include "logger.hh"
0e933ef0 8#include "lua-base4.hh"
f3c18728 9#include "rec-lua-conf.hh"
3e61e7f7 10#include "sortlist.hh"
ad42489c 11#include "filterpo.hh"
12#include "syncres.hh"
13#include "rpzloader.hh"
98c9ec39 14#include "base64.hh"
aa7929a3 15#include "remote_logger.hh"
52ad9eea 16#include "validate.hh"
e48c6b8a 17#include "validate-recursor.hh"
f2234140 18#include "root-dnssec.hh"
3e61e7f7 19
a7f98e34 20GlobalStateHolder<LuaConfigItems> g_luaconfs;
f3c18728 21
22/* SO HOW DOES THIS WORK! AND PLEASE PAY ATTENTION!
23 This function can be called at any time. It is expected to overwrite all the contents
24 of LuaConfigItems, which is held in a GlobalStateHolder for RCU properties.
25
26 This function can be called again at a later date, so you must make sure that anything you
27 allow to be configured from here lives in g_luaconfs AND NOWHERE ELSE.
28
29 If someone loads an empty Lua file, the default LuaConfigItems struct MUST MAKE SENSE.
30
31 To make this easy on you, here is a LuaConfigItems constructor where you
32 can set sane defaults:
33*/
34
35LuaConfigItems::LuaConfigItems()
36{
03bf7abb 37 DNSName root("."); // don't use g_rootdnsname here, it might not exist yet
a7f98e34
O
38 for (const auto& dsRecord : rootDSs) {
39 auto ds = std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsRecord));
03bf7abb 40 dsAnchors[root].insert(*ds);
f2234140 41 }
f3c18728 42}
43
ad42489c 44/* DID YOU READ THE STORY ABOVE? */
45
babe9430
OM
46bool operator==(const ProtobufExportConfig& configA, const ProtobufExportConfig& configB)
47{
48 // clang-format off
49 return configA.exportTypes == configB.exportTypes &&
50 configA.servers == configB.servers &&
51 configA.maxQueuedEntries == configB.maxQueuedEntries &&
52 configA.timeout == configB.timeout &&
53 configA.reconnectWaitTime == configB.reconnectWaitTime &&
54 configA.asyncConnect == configB.asyncConnect &&
55 configA.enabled == configB.enabled &&
56 configA.logQueries == configB.logQueries &&
57 configA.logResponses == configB.logResponses &&
58 configA.taggedOnly == configB.taggedOnly &&
59 configA.logMappedFrom == configB.logMappedFrom;
60 // clang-format on
61}
62
63bool operator!=(const ProtobufExportConfig& configA, const ProtobufExportConfig& configB)
64{
65 return !(configA == configB);
66}
67
afaf1b5d
FM
68bool operator==(const FrameStreamExportConfig& configA, const FrameStreamExportConfig& configB)
69{
70 // clang-format off
71 return configA.enabled == configB.enabled &&
72 configA.logQueries == configB.logQueries &&
73 configA.logResponses == configB.logResponses &&
678915f2
OM
74 configA.logNODs == configB.logNODs &&
75 configA.logUDRs == configB.logUDRs &&
afaf1b5d
FM
76 configA.bufferHint == configB.bufferHint &&
77 configA.flushTimeout == configB.flushTimeout &&
78 configA.inputQueueSize == configB.inputQueueSize &&
79 configA.outputQueueSize == configB.outputQueueSize &&
80 configA.queueNotifyThreshold == configB.queueNotifyThreshold &&
81 configA.reopenInterval == configB.reopenInterval &&
82 configA.servers == configB.servers;
83 // clang-format on
84}
85
86bool operator!=(const FrameStreamExportConfig& configA, const FrameStreamExportConfig& configB)
87{
88 return !(configA == configB);
89}
90
ad42489c 91template <typename C>
92typename C::value_type::second_type constGet(const C& c, const std::string& name)
93{
94 auto iter = c.find(name);
a7f98e34 95 if (iter == c.end())
ad42489c 96 return 0;
97 return iter->second;
98}
99
a7f98e34 100typedef std::unordered_map<std::string, boost::variant<bool, uint32_t, std::string, std::vector<std::pair<int, std::string>>>> rpzOptions_t;
6a99b9a4 101
af231ceb 102static void parseRPZParameters(rpzOptions_t& have, std::shared_ptr<DNSFilterEngine::Zone>& zone, std::string& polName, boost::optional<DNSFilterEngine::Policy>& defpol, bool& defpolOverrideLocal, uint32_t& maxTTL)
8f618901 103{
07984b95 104 if (have.count("policyName") != 0) {
d122dac0 105 polName = boost::get<std::string>(have["policyName"]);
8f618901 106 }
07984b95 107 if (have.count("defpol") != 0) {
a7f98e34 108 defpol = DNSFilterEngine::Policy();
d122dac0 109 defpol->d_kind = (DNSFilterEngine::PolicyKind)boost::get<uint32_t>(have["defpol"]);
b502d522 110 defpol->setName(polName);
a7f98e34 111 if (defpol->d_kind == DNSFilterEngine::PolicyKind::Custom) {
d525b58b
KM
112 defpol->d_custom.push_back(DNSRecordContent::make(QType::CNAME, QClass::IN,
113 boost::get<string>(have["defcontent"])));
8f618901 114
07984b95 115 if (have.count("defttl") != 0) {
d122dac0 116 defpol->d_ttl = static_cast<int32_t>(boost::get<uint32_t>(have["defttl"]));
07984b95
OM
117 }
118 else {
8f618901 119 defpol->d_ttl = -1; // get it from the zone
07984b95 120 }
8f618901 121 }
d122dac0 122
07984b95 123 if (have.count("defpolOverrideLocalData") != 0) {
d122dac0
RG
124 defpolOverrideLocal = boost::get<bool>(have["defpolOverrideLocalData"]);
125 }
8f618901 126 }
07984b95 127 if (have.count("maxTTL") != 0) {
d122dac0 128 maxTTL = boost::get<uint32_t>(have["maxTTL"]);
8f618901 129 }
07984b95 130 if (have.count("zoneSizeHint") != 0) {
af231ceb
RG
131 auto zoneSizeHint = static_cast<size_t>(boost::get<uint32_t>(have["zoneSizeHint"]));
132 if (zoneSizeHint > 0) {
133 zone->reserve(zoneSizeHint);
134 }
8f618901 135 }
07984b95 136 if (have.count("tags") != 0) {
b502d522 137 const auto tagsTable = boost::get<std::vector<std::pair<int, std::string>>>(have["tags"]);
af231ceb 138 std::unordered_set<std::string> tags;
b502d522
RG
139 for (const auto& tag : tagsTable) {
140 tags.insert(tag.second);
141 }
af231ceb 142 zone->setTags(std::move(tags));
b502d522 143 }
07984b95 144 if (have.count("overridesGettag") != 0) {
af231ceb
RG
145 zone->setPolicyOverridesGettag(boost::get<bool>(have["overridesGettag"]));
146 }
07984b95 147 if (have.count("extendedErrorCode") != 0) {
e77faee1
RG
148 auto code = boost::get<uint32_t>(have["extendedErrorCode"]);
149 if (code > std::numeric_limits<uint16_t>::max()) {
150 throw std::runtime_error("Invalid extendedErrorCode value " + std::to_string(code) + " in RPZ configuration");
151 }
152
153 zone->setExtendedErrorCode(static_cast<uint16_t>(code));
07984b95 154 if (have.count("extendedErrorExtra") != 0) {
af231ceb
RG
155 zone->setExtendedErrorExtra(boost::get<std::string>(have["extendedErrorExtra"]));
156 }
db27d56f 157 }
07984b95 158 if (have.count("includeSOA") != 0) {
46572de5
OM
159 zone->setIncludeSOA(boost::get<bool>(have["includeSOA"]));
160 }
8f618901
RG
161}
162
a7f98e34 163typedef std::unordered_map<std::string, boost::variant<bool, uint64_t, std::string, std::vector<std::pair<int, std::string>>>> protobufOptions_t;
f1c7929a
RG
164
165static void parseProtobufOptions(boost::optional<protobufOptions_t> vars, ProtobufExportConfig& config)
166{
167 if (!vars) {
168 return;
169 }
170
171 if (vars->count("timeout")) {
172 config.timeout = boost::get<uint64_t>((*vars)["timeout"]);
173 }
174
175 if (vars->count("maxQueuedEntries")) {
176 config.maxQueuedEntries = boost::get<uint64_t>((*vars)["maxQueuedEntries"]);
177 }
178
179 if (vars->count("reconnectWaitTime")) {
180 config.reconnectWaitTime = boost::get<uint64_t>((*vars)["reconnectWaitTime"]);
181 }
182
183 if (vars->count("asyncConnect")) {
184 config.asyncConnect = boost::get<bool>((*vars)["asyncConnect"]);
185 }
186
187 if (vars->count("taggedOnly")) {
188 config.taggedOnly = boost::get<bool>((*vars)["taggedOnly"]);
189 }
190
191 if (vars->count("logQueries")) {
192 config.logQueries = boost::get<bool>((*vars)["logQueries"]);
193 }
194
195 if (vars->count("logResponses")) {
196 config.logResponses = boost::get<bool>((*vars)["logResponses"]);
197 }
0bd2e252 198
e81063e5
OM
199 if (vars->count("logMappedFrom")) {
200 config.logMappedFrom = boost::get<bool>((*vars)["logMappedFrom"]);
201 }
202
0bd2e252
RG
203 if (vars->count("exportTypes")) {
204 config.exportTypes.clear();
205
a7f98e34 206 auto types = boost::get<std::vector<std::pair<int, std::string>>>((*vars)["exportTypes"]);
0bd2e252 207 for (const auto& pair : types) {
0e933ef0 208 const auto& type = pair.second;
0bd2e252 209
0e933ef0
OM
210 QType qtype;
211 try {
212 qtype = std::stoul(type);
0bd2e252 213 }
0e933ef0
OM
214 catch (const std::exception& ex) {
215 qtype = QType::chartocode(type.c_str());
216 if (qtype == 0) {
217 throw std::runtime_error("Unknown QType '" + type + "' in protobuf's export types");
218 }
219 }
220 config.exportTypes.insert(qtype);
0bd2e252
RG
221 }
222 }
f1c7929a
RG
223}
224
b9fa43e0 225#ifdef HAVE_FSTRM
a7f98e34 226typedef std::unordered_map<std::string, boost::variant<bool, uint64_t, std::string, std::vector<std::pair<int, std::string>>>> frameStreamOptions_t;
b9fa43e0
OM
227
228static void parseFrameStreamOptions(boost::optional<frameStreamOptions_t> vars, FrameStreamExportConfig& config)
229{
230 if (!vars) {
231 return;
232 }
573f4ff0
OM
233
234 if (vars->count("logQueries")) {
235 config.logQueries = boost::get<bool>((*vars)["logQueries"]);
236 }
237 if (vars->count("logResponses")) {
238 config.logResponses = boost::get<bool>((*vars)["logResponses"]);
239 }
9489e2b5
CHB
240 if (vars->count("logNODs")) {
241 config.logNODs = boost::get<bool>((*vars)["logNODs"]);
242 }
243 if (vars->count("logUDRs")) {
244 config.logUDRs = boost::get<bool>((*vars)["logUDRs"]);
245 }
573f4ff0
OM
246
247 if (vars->count("bufferHint")) {
248 config.bufferHint = boost::get<uint64_t>((*vars)["bufferHint"]);
249 }
250 if (vars->count("flushTimeout")) {
251 config.flushTimeout = boost::get<uint64_t>((*vars)["flushTimeout"]);
252 }
253 if (vars->count("inputQueueSize")) {
254 config.inputQueueSize = boost::get<uint64_t>((*vars)["inputQueueSize"]);
255 }
256 if (vars->count("outputQueueSize")) {
257 config.outputQueueSize = boost::get<uint64_t>((*vars)["outputQueueSize"]);
258 }
259 if (vars->count("queueNotifyThreshold")) {
260 config.queueNotifyThreshold = boost::get<uint64_t>((*vars)["queueNotifyThreshold"]);
261 }
262 if (vars->count("reopenInterval")) {
263 config.reopenInterval = boost::get<uint64_t>((*vars)["reopenInterval"]);
264 }
b9fa43e0
OM
265}
266#endif /* HAVE_FSTRM */
267
3d324e00 268static void rpzPrimary(LuaConfigItems& lci, luaConfigDelayedThreads& delayedThreads, const boost::variant<string, std::vector<std::pair<int, string>>>& primaries_, const string& zoneName, boost::optional<rpzOptions_t> options)
4f2aa09a
OM
269{
270 boost::optional<DNSFilterEngine::Policy> defpol;
271 bool defpolOverrideLocal = true;
272 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
273 TSIGTriplet tt;
a7f98e34 274 uint32_t refresh = 0;
4f2aa09a
OM
275 size_t maxReceivedXFRMBytes = 0;
276 uint16_t axfrTimeout = 20;
277 uint32_t maxTTL = std::numeric_limits<uint32_t>::max();
278 ComboAddress localAddress;
3d324e00
O
279 std::vector<ComboAddress> primaries;
280 if (primaries_.type() == typeid(string)) {
281 primaries.push_back(ComboAddress(boost::get<std::string>(primaries_), 53));
4f2aa09a
OM
282 }
283 else {
3d324e00
O
284 for (const auto& primary : boost::get<std::vector<std::pair<int, std::string>>>(primaries_)) {
285 primaries.push_back(ComboAddress(primary.second, 53));
4f2aa09a
OM
286 }
287 }
288
289 size_t zoneIdx;
290 std::string dumpFile;
d06dcda4 291 std::shared_ptr<const SOARecordContent> sr = nullptr;
4f2aa09a
OM
292
293 try {
294 std::string seedFile;
295 std::string polName(zoneName);
296
297 if (options) {
298 auto& have = *options;
299 parseRPZParameters(have, zone, polName, defpol, defpolOverrideLocal, maxTTL);
300
a7f98e34
O
301 if (have.count("tsigname")) {
302 tt.name = DNSName(toLower(boost::get<string>(have["tsigname"])));
303 tt.algo = DNSName(toLower(boost::get<string>(have["tsigalgo"])));
304 if (B64Decode(boost::get<string>(have["tsigsecret"]), tt.secret))
4f2aa09a
OM
305 throw std::runtime_error("TSIG secret is not valid Base-64 encoded");
306 }
307
a7f98e34 308 if (have.count("refresh")) {
4f2aa09a
OM
309 refresh = boost::get<uint32_t>(have["refresh"]);
310 if (refresh == 0) {
62b191dc
OM
311 SLOG(g_log << Logger::Warning << "rpzPrimary refresh value of 0 ignored" << endl,
312 lci.d_slog->info(Logr::Warning, "rpzPrimary refresh value of 0 ignored"));
4f2aa09a
OM
313 }
314 }
315
a7f98e34 316 if (have.count("maxReceivedMBytes")) {
4f2aa09a
OM
317 maxReceivedXFRMBytes = static_cast<size_t>(boost::get<uint32_t>(have["maxReceivedMBytes"]));
318 }
319
a7f98e34 320 if (have.count("localAddress")) {
4f2aa09a
OM
321 localAddress = ComboAddress(boost::get<string>(have["localAddress"]));
322 }
323
a7f98e34 324 if (have.count("axfrTimeout")) {
4f2aa09a
OM
325 axfrTimeout = static_cast<uint16_t>(boost::get<uint32_t>(have["axfrTimeout"]));
326 }
327
a7f98e34 328 if (have.count("seedFile")) {
4f2aa09a
OM
329 seedFile = boost::get<std::string>(have["seedFile"]);
330 }
331
a7f98e34 332 if (have.count("dumpFile")) {
4f2aa09a
OM
333 dumpFile = boost::get<std::string>(have["dumpFile"]);
334 }
335 }
336
337 if (localAddress != ComboAddress()) {
3d324e00
O
338 // We were passed a localAddress, check if its AF matches the primaries'
339 for (const auto& primary : primaries) {
340 if (localAddress.sin4.sin_family != primary.sin4.sin_family) {
a7f98e34 341 throw PDNSException("Primary address(" + primary.toString() + ") is not of the same Address Family as the local address (" + localAddress.toString() + ").");
4f2aa09a
OM
342 }
343 }
344 }
345
346 DNSName domain(zoneName);
347 zone->setDomain(domain);
348 zone->setName(polName);
349 zoneIdx = lci.dfe.addZone(zone);
350
43f91cad 351 auto log = lci.d_slog->withValues("seedfile", Logging::Loggable(seedFile), "zone", Logging::Loggable(zoneName));
4f2aa09a 352 if (!seedFile.empty()) {
62b191dc
OM
353 SLOG(g_log << Logger::Info << "Pre-loading RPZ zone " << zoneName << " from seed file '" << seedFile << "'" << endl,
354 log->info(Logr::Info, "Pre-loading RPZ zone from seed file"));
4f2aa09a
OM
355 try {
356 sr = loadRPZFromFile(seedFile, zone, defpol, defpolOverrideLocal, maxTTL);
357
358 if (zone->getDomain() != domain) {
359 throw PDNSException("The RPZ zone " + zoneName + " loaded from the seed file (" + zone->getDomain().toString() + ") does not match the one passed in parameter (" + domain.toString() + ")");
360 }
361
362 if (sr == nullptr) {
363 throw PDNSException("The RPZ zone " + zoneName + " loaded from the seed file (" + zone->getDomain().toString() + ") has no SOA record");
364 }
365 }
a7f98e34 366 catch (const PDNSException& e) {
62b191dc 367 SLOG(g_log << Logger::Warning << "Unable to pre-load RPZ zone " << zoneName << " from seed file '" << seedFile << "': " << e.reason << endl,
84d24234 368 log->error(Logr::Warning, e.reason, "Exception while pre-loading RPZ zone", "exception", Logging::Loggable("PDNSException")));
a47cc75d
O
369 zone->clear();
370 }
a7f98e34 371 catch (const std::exception& e) {
62b191dc 372 SLOG(g_log << Logger::Warning << "Unable to pre-load RPZ zone " << zoneName << " from seed file '" << seedFile << "': " << e.what() << endl,
84d24234 373 log->error(Logr::Warning, e.what(), "Exception while pre-loading RPZ zone", "exception", Logging::Loggable("std::exception")));
a47cc75d 374 zone->clear();
4f2aa09a
OM
375 }
376 }
377 }
a7f98e34 378 catch (const std::exception& e) {
62b191dc 379 SLOG(g_log << Logger::Error << "Problem configuring 'rpzPrimary': " << e.what() << endl,
c42e8958 380 lci.d_slog->error(Logr::Error, e.what(), "Exception configuring 'rpzPrimary'", "exception", Logging::Loggable("std::exception")));
4f2aa09a 381 }
a7f98e34 382 catch (const PDNSException& e) {
62b191dc 383 SLOG(g_log << Logger::Error << "Problem configuring 'rpzPrimary': " << e.reason << endl,
c42e8958 384 lci.d_slog->error(Logr::Error, e.reason, "Exception configuring 'rpzPrimary'", Logging::Loggable("PDNSException")));
4f2aa09a
OM
385 }
386
0b0882f5 387 delayedThreads.rpzPrimaryThreads.emplace_back(primaries, defpol, defpolOverrideLocal, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes, localAddress, axfrTimeout, refresh, sr, dumpFile);
4f2aa09a
OM
388}
389
0b1bb97e 390// A wrapper class that loads the standard Lua defintions into the context, so that we can use things like pdns.A
0e933ef0
OM
391class RecLuaConfigContext : public BaseLua4
392{
393public:
394 RecLuaConfigContext()
395 {
396 prepareContext();
397 }
0b1bb97e 398 void postPrepareContext() override
0e933ef0 399 {
1b47f291
OM
400 // clang-format off
401 d_pd.push_back({"AdditionalMode", in_t{
402 {"Ignore", static_cast<int>(AdditionalMode::Ignore)},
403 {"CacheOnly", static_cast<int>(AdditionalMode::CacheOnly)},
404 {"CacheOnlyRequireAuth", static_cast<int>(AdditionalMode::CacheOnlyRequireAuth)},
405 {"ResolveImmediately", static_cast<int>(AdditionalMode::ResolveImmediately)},
406 {"ResolveDeferred", static_cast<int>(AdditionalMode::ResolveDeferred)}
407 }});
0e933ef0
OM
408 }
409 void postLoad() override
410 {
411 }
0b1bb97e 412 LuaContext* operator->()
0e933ef0 413 {
0b1bb97e 414 return d_lw.get();
0e933ef0
OM
415 }
416};
417
e81063e5 418void loadRecursorLuaConfig(const std::string& fname, luaConfigDelayedThreads& delayedThreads, ProxyMapping& proxyMapping)
3e61e7f7 419{
f3c18728 420 LuaConfigItems lci;
62b191dc 421 lci.d_slog = g_slog->withName("luaconfig");
f3c18728 422
0e933ef0
OM
423 RecLuaConfigContext Lua;
424
a7f98e34 425 if (fname.empty())
3e61e7f7 426 return;
427 ifstream ifs(fname);
a7f98e34
O
428 if (!ifs)
429 throw PDNSException("Cannot open file '" + fname + "': " + stringerror());
0f5785a6 430
63341e8d
RG
431 auto luaconfsLocal = g_luaconfs.getLocal();
432 lci.generation = luaconfsLocal->generation + 1;
433
0b1bb97e 434 Lua->writeFunction("clearSortlist", [&lci]() { lci.sortlist.clear(); });
a7f98e34 435
3e61e7f7 436 /* we can get: "1.2.3.4"
437 {"1.2.3.4", "4.5.6.7"}
b8d0d0db 438 {"1.2.3.4", {"4.5.6.7", "8.9.10.11"}}
3e61e7f7 439 */
440
a7f98e34
O
441 map<string, DNSFilterEngine::PolicyKind> pmap{
442 {"NoAction", DNSFilterEngine::PolicyKind::NoAction},
ad42489c 443 {"Drop", DNSFilterEngine::PolicyKind::Drop},
444 {"NXDOMAIN", DNSFilterEngine::PolicyKind::NXDOMAIN},
445 {"NODATA", DNSFilterEngine::PolicyKind::NODATA},
446 {"Truncate", DNSFilterEngine::PolicyKind::Truncate},
a7f98e34 447 {"Custom", DNSFilterEngine::PolicyKind::Custom}};
0b1bb97e 448 Lua->writeVariable("Policy", pmap);
ad42489c 449
0b1bb97e 450 Lua->writeFunction("rpzFile", [&lci](const string& filename, boost::optional<rpzOptions_t> options) {
62b191dc 451 auto log = lci.d_slog->withValues("file", Logging::Loggable(filename));
a7f98e34
O
452 try {
453 boost::optional<DNSFilterEngine::Policy> defpol;
454 bool defpolOverrideLocal = true;
455 std::string polName("rpzFile");
456 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
457 uint32_t maxTTL = std::numeric_limits<uint32_t>::max();
458 if (options) {
459 auto& have = *options;
460 parseRPZParameters(have, zone, polName, defpol, defpolOverrideLocal, maxTTL);
ad42489c 461 }
62b191dc
OM
462 SLOG(g_log << Logger::Warning << "Loading RPZ from file '" << filename << "'" << endl,
463 log->info(Logr::Info, "Loading RPZ from file"));
a7f98e34
O
464 zone->setName(polName);
465 loadRPZFromFile(filename, zone, defpol, defpolOverrideLocal, maxTTL);
466 lci.dfe.addZone(zone);
62b191dc
OM
467 SLOG(g_log << Logger::Warning << "Done loading RPZ from file '" << filename << "'" << endl,
468 log->info(Logr::Info, "Done loading RPZ from file"));
a7f98e34
O
469 }
470 catch (const std::exception& e) {
62b191dc 471 SLOG(g_log << Logger::Error << "Unable to load RPZ zone from '" << filename << "': " << e.what() << endl,
96cebcf6 472 log->error(Logr::Error, e.what(), "Exception while loading RPZ zone from file"));
a7f98e34
O
473 }
474 });
ad42489c 475
0b1bb97e 476 Lua->writeFunction("rpzMaster", [&lci, &delayedThreads](const boost::variant<string, std::vector<std::pair<int, string>>>& primaries_, const string& zoneName, boost::optional<rpzOptions_t> options) {
62b191dc
OM
477 SLOG(g_log << Logger::Warning << "'rpzMaster' is deprecated and will be removed in a future release, use 'rpzPrimary' instead" << endl,
478 lci.d_slog->info(Logr::Warning, "'rpzMaster' is deprecated and will be removed in a future release, use 'rpzPrimary' instead"));
3d324e00 479 rpzPrimary(lci, delayedThreads, primaries_, zoneName, options);
a7f98e34 480 });
0b1bb97e 481 Lua->writeFunction("rpzPrimary", [&lci, &delayedThreads](const boost::variant<string, std::vector<std::pair<int, string>>>& primaries_, const string& zoneName, boost::optional<rpzOptions_t> options) {
3d324e00 482 rpzPrimary(lci, delayedThreads, primaries_, zoneName, options);
a7f98e34 483 });
ad42489c 484
e807cd1e
O
485 typedef std::unordered_map<std::string, boost::variant<uint32_t, std::string>> zoneToCacheOptions_t;
486
0b1bb97e 487 Lua->writeFunction("zoneToCache", [&lci](const string& zoneName, const string& method, const boost::variant<string, std::vector<std::pair<int, string>>>& srcs, boost::optional<zoneToCacheOptions_t> options) {
e807cd1e
O
488 try {
489 RecZoneToCache::Config conf;
a0fc9882 490 DNSName validZoneName(zoneName);
e807cd1e 491 conf.d_zone = zoneName;
a0fc9882
O
492 const set<string> methods = {"axfr", "url", "file"};
493 if (methods.count(method) == 0) {
494 throw std::runtime_error("unknwon method '" + method + "'");
495 }
e807cd1e 496 conf.d_method = method;
48defb61
OM
497 if (srcs.type() == typeid(std::string)) {
498 conf.d_sources.push_back(boost::get<std::string>(srcs));
e807cd1e
O
499 }
500 else {
48defb61
OM
501 for (const auto& src : boost::get<std::vector<std::pair<int, std::string>>>(srcs)) {
502 conf.d_sources.push_back(src.second);
e807cd1e
O
503 }
504 }
a0fc9882
O
505 if (conf.d_sources.size() == 0) {
506 throw std::runtime_error("at least one source required");
507 }
e807cd1e
O
508 if (options) {
509 auto& have = *options;
510 if (have.count("timeout")) {
a0fc9882 511 conf.d_timeout = boost::get<uint32_t>(have.at("timeout"));
e807cd1e
O
512 }
513 if (have.count("tsigname")) {
a0fc9882
O
514 conf.d_tt.name = DNSName(toLower(boost::get<string>(have.at("tsigname"))));
515 conf.d_tt.algo = DNSName(toLower(boost::get<string>(have.at("tsigalgo"))));
516 if (B64Decode(boost::get<string>(have.at("tsigsecret")), conf.d_tt.secret)) {
e807cd1e
O
517 throw std::runtime_error("TSIG secret is not valid Base-64 encoded");
518 }
519 }
520 if (have.count("maxReceivedMBytes")) {
a0fc9882 521 conf.d_maxReceivedBytes = static_cast<size_t>(boost::get<uint32_t>(have.at("maxReceivedMBytes")));
e807cd1e
O
522 conf.d_maxReceivedBytes *= 1024 * 1024;
523 }
524 if (have.count("localAddress")) {
a0fc9882 525 conf.d_local = ComboAddress(boost::get<string>(have.at("localAddress")));
e807cd1e 526 }
48defb61 527 if (have.count("refreshPeriod")) {
a0fc9882 528 conf.d_refreshPeriod = boost::get<uint32_t>(have.at("refreshPeriod"));
48defb61
OM
529 }
530 if (have.count("retryOnErrorPeriod")) {
a0fc9882 531 conf.d_retryOnError = boost::get<uint32_t>(have.at("retryOnErrorPeriod"));
48defb61 532 }
574447ad
OM
533 const map<string, pdns::ZoneMD::Config> nameToVal = {
534 {"ignore", pdns::ZoneMD::Config::Ignore},
94223b01 535 {"validate", pdns::ZoneMD::Config::Validate},
af5b15bc 536 {"require", pdns::ZoneMD::Config::Require},
574447ad
OM
537 };
538 if (have.count("zonemd")) {
539 string zonemdValidation = boost::get<string>(have.at("zonemd"));
5e7dd5e9
OM
540 auto it = nameToVal.find(zonemdValidation);
541 if (it == nameToVal.end()) {
6ee50109 542 throw std::runtime_error(zonemdValidation + " is not a valid value for `zonemd`");
b8d0d0db
OM
543 }
544 else {
5e7dd5e9
OM
545 conf.d_zonemd = it->second;
546 }
547 }
6ee50109
OM
548 if (have.count("dnssec")) {
549 string dnssec = boost::get<string>(have.at("dnssec"));
574447ad
OM
550 auto it = nameToVal.find(dnssec);
551 if (it == nameToVal.end()) {
6ee50109 552 throw std::runtime_error(dnssec + " is not a valid value for `dnssec`");
574447ad
OM
553 }
554 else {
555 conf.d_dnssec = it->second;
556 }
557 }
e807cd1e
O
558 }
559
b8d0d0db 560 lci.ztcConfigs[validZoneName] = conf;
e807cd1e 561 }
a0fc9882 562 catch (const std::exception& e) {
f7631ff1
OM
563 SLOG(g_log << Logger::Error << "Problem configuring zoneToCache for zone '" << zoneName << "': " << e.what() << endl,
564 lci.d_slog->error(Logr::Error, e.what(), "Problem configuring zoneToCache", "zone", Logging::Loggable(zoneName),
565 "exception", Logging::Loggable("std::exception")));
e807cd1e
O
566 }
567 });
a0fc9882 568
a7f98e34 569 typedef vector<pair<int, boost::variant<string, vector<pair<int, string>>>>> argvec_t;
0b1bb97e
OM
570 Lua->writeFunction("addSortList",
571 [&lci](const std::string& formask_,
572 const boost::variant<string, argvec_t>& masks,
573 boost::optional<int> order_) {
574 try {
575 Netmask formask(formask_);
576 int order = order_ ? (*order_) : lci.sortlist.getMaxOrder(formask) + 1;
577 if (auto str = boost::get<string>(&masks))
578 lci.sortlist.addEntry(formask, Netmask(*str), order);
579 else {
580
581 auto vec = boost::get<argvec_t>(&masks);
582 for (const auto& e : *vec) {
583 if (auto s = boost::get<string>(&e.second)) {
584 lci.sortlist.addEntry(formask, Netmask(*s), order);
585 }
586 else {
587 const auto& v = boost::get<vector<pair<int, string>>>(e.second);
588 for (const auto& entry : v)
589 lci.sortlist.addEntry(formask, Netmask(entry.second), order);
590 }
591 ++order;
592 }
593 }
594 }
595 catch (std::exception& e) {
f7631ff1
OM
596 SLOG(g_log << Logger::Error << "Error in addSortList: " << e.what() << endl,
597 lci.d_slog->error(Logr::Error, e.what(), "Error in addSortList", "exception", Logging::Loggable("std::exception")));
0b1bb97e
OM
598 }
599 });
600
601 Lua->writeFunction("addTA", [&lci](const std::string& who, const std::string& what) {
a7f98e34
O
602 warnIfDNSSECDisabled("Warning: adding Trust Anchor for DNSSEC (addTA), but dnssec is set to 'off'!");
603 DNSName zone(who);
604 auto ds = std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(what));
605 lci.dsAnchors[zone].insert(*ds);
190e0d9a
PL
606 });
607
0b1bb97e 608 Lua->writeFunction("clearTA", [&lci](boost::optional<string> who) {
a7f98e34
O
609 warnIfDNSSECDisabled("Warning: removing Trust Anchor for DNSSEC (clearTA), but dnssec is set to 'off'!");
610 if (who)
611 lci.dsAnchors.erase(DNSName(*who));
612 else
613 lci.dsAnchors.clear();
614 });
190e0d9a
PL
615
616 /* Remove in 4.3 */
0b1bb97e 617 Lua->writeFunction("addDS", [&lci](const std::string& who, const std::string& what) {
a7f98e34 618 warnIfDNSSECDisabled("Warning: adding Trust Anchor for DNSSEC (addDS), but dnssec is set to 'off'!");
f7631ff1
OM
619 SLOG(g_log << Logger::Warning << "addDS is deprecated and will be removed in the future, switch to addTA" << endl,
620 lci.d_slog->info(Logr::Warning, "addDS is deprecated and will be removed in the future, switch to addTA"));
a7f98e34
O
621 DNSName zone(who);
622 auto ds = std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(what));
623 lci.dsAnchors[zone].insert(*ds);
52ad9eea 624 });
2ac8ae89 625
190e0d9a 626 /* Remove in 4.3 */
0b1bb97e 627 Lua->writeFunction("clearDS", [&lci](boost::optional<string> who) {
f7631ff1
OM
628 SLOG(g_log << Logger::Warning << "clearDS is deprecated and will be removed in the future, switch to clearTA" << endl,
629 lci.d_slog->info(Logr::Warning, "clearDS is deprecated and will be removed in the future, switch to clearTA"));
a7f98e34
O
630 warnIfDNSSECDisabled("Warning: removing Trust Anchor for DNSSEC (clearDS), but dnssec is set to 'off'!");
631 if (who)
632 lci.dsAnchors.erase(DNSName(*who));
633 else
634 lci.dsAnchors.clear();
635 });
2ac8ae89 636
0b1bb97e 637 Lua->writeFunction("addNTA", [&lci](const std::string& who, const boost::optional<std::string> why) {
a7f98e34
O
638 warnIfDNSSECDisabled("Warning: adding Negative Trust Anchor for DNSSEC (addNTA), but dnssec is set to 'off'!");
639 if (why)
640 lci.negAnchors[DNSName(who)] = static_cast<string>(*why);
641 else
642 lci.negAnchors[DNSName(who)] = "";
643 });
1bd49828 644
0b1bb97e 645 Lua->writeFunction("clearNTA", [&lci](boost::optional<string> who) {
a7f98e34
O
646 warnIfDNSSECDisabled("Warning: removing Negative Trust Anchor for DNSSEC (clearNTA), but dnssec is set to 'off'!");
647 if (who)
648 lci.negAnchors.erase(DNSName(*who));
649 else
650 lci.negAnchors.clear();
651 });
1bd49828 652
0b1bb97e 653 Lua->writeFunction("readTrustAnchorsFromFile", [&lci](const std::string& fnamearg, const boost::optional<uint32_t> interval) {
a7f98e34
O
654 uint32_t realInterval = 24;
655 if (interval) {
656 realInterval = static_cast<uint32_t>(*interval);
657 }
658 warnIfDNSSECDisabled("Warning: reading Trust Anchors from file (readTrustAnchorsFromFile), but dnssec is set to 'off'!");
659 lci.trustAnchorFileInfo.fname = fnamearg;
660 lci.trustAnchorFileInfo.interval = realInterval;
62b191dc 661 updateTrustAnchorsFromFile(fnamearg, lci.dsAnchors, lci.d_slog);
a7f98e34 662 });
8f29eeaa 663
0b1bb97e 664 Lua->writeFunction("setProtobufMasks", [&lci](const uint8_t maskV4, uint8_t maskV6) {
a7f98e34
O
665 lci.protobufMaskV4 = maskV4;
666 lci.protobufMaskV6 = maskV6;
667 });
f1c7929a 668
0b1bb97e 669 Lua->writeFunction("protobufServer", [&lci](boost::variant<const std::string, const std::unordered_map<int, std::string>> servers, boost::optional<protobufOptions_t> vars) {
a7f98e34 670 if (!lci.protobufExportConfig.enabled) {
b773359c 671
a7f98e34 672 lci.protobufExportConfig.enabled = true;
b773359c 673
a7f98e34
O
674 try {
675 if (servers.type() == typeid(std::string)) {
676 auto server = boost::get<const std::string>(servers);
b773359c 677
a7f98e34 678 lci.protobufExportConfig.servers.emplace_back(server);
aa7929a3
RG
679 }
680 else {
a7f98e34
O
681 auto serversMap = boost::get<const std::unordered_map<int, std::string>>(servers);
682 for (const auto& serverPair : serversMap) {
683 lci.protobufExportConfig.servers.emplace_back(serverPair.second);
684 }
aa7929a3 685 }
4898a348 686
a7f98e34
O
687 parseProtobufOptions(vars, lci.protobufExportConfig);
688 }
689 catch (std::exception& e) {
62b191dc 690 SLOG(g_log << Logger::Error << "Error while adding protobuf logger: " << e.what() << endl,
84d24234 691 lci.d_slog->error(Logr::Error, e.what(), "Exception while adding protobuf logger", "exception", Logging::Loggable("std::exception")));
a7f98e34
O
692 }
693 catch (PDNSException& e) {
62b191dc 694 SLOG(g_log << Logger::Error << "Error while adding protobuf logger: " << e.reason << endl,
84d24234 695 lci.d_slog->error(Logr::Error, e.reason, "Exception while adding protobuf logger", "exception", Logging::Loggable("PDNSException")));
a7f98e34
O
696 }
697 }
698 else {
62b191dc
OM
699 SLOG(g_log << Logger::Error << "Only one protobufServer() directive can be configured, we already have " << lci.protobufExportConfig.servers.at(0).toString() << endl,
700 lci.d_slog->info(Logr::Error, "Only one protobufServer() directive can be configured", "existing", Logging::Loggable(lci.protobufExportConfig.servers.at(0).toString())));
a7f98e34
O
701 }
702 });
b773359c 703
0b1bb97e 704 Lua->writeFunction("outgoingProtobufServer", [&lci](boost::variant<const std::string, const std::unordered_map<int, std::string>> servers, boost::optional<protobufOptions_t> vars) {
a7f98e34 705 if (!lci.outgoingProtobufExportConfig.enabled) {
b773359c 706
a7f98e34 707 lci.outgoingProtobufExportConfig.enabled = true;
b773359c 708
a7f98e34
O
709 try {
710 if (servers.type() == typeid(std::string)) {
711 auto server = boost::get<const std::string>(servers);
b773359c 712
a7f98e34
O
713 lci.outgoingProtobufExportConfig.servers.emplace_back(server);
714 }
715 else {
716 auto serversMap = boost::get<const std::unordered_map<int, std::string>>(servers);
717 for (const auto& serverPair : serversMap) {
718 lci.outgoingProtobufExportConfig.servers.emplace_back(serverPair.second);
b773359c 719 }
a7f98e34
O
720 }
721
722 parseProtobufOptions(vars, lci.outgoingProtobufExportConfig);
aa7929a3 723 }
a7f98e34 724 catch (std::exception& e) {
62b191dc
OM
725 SLOG(g_log << Logger::Error << "Error while starting outgoing protobuf logger: " << e.what() << endl,
726 lci.d_slog->error(Logr::Error, "Exception while starting outgoing protobuf logger", "exception", Logging::Loggable("std::exception")));
a7f98e34
O
727 }
728 catch (PDNSException& e) {
62b191dc
OM
729 SLOG(g_log << Logger::Error << "Error while starting outgoing protobuf logger: " << e.reason << endl,
730 lci.d_slog->error(Logr::Error, "Exception while starting outgoing protobuf logger", "exception", Logging::Loggable("PDNSException")));
aa7929a3 731 }
a7f98e34
O
732 }
733 else {
62b191dc
OM
734 SLOG(g_log << Logger::Error << "Only one outgoingProtobufServer() directive can be configured, we already have " << lci.outgoingProtobufExportConfig.servers.at(0).toString() << endl,
735 lci.d_slog->info(Logr::Error, "Only one outgoingProtobufServer() directive can be configured", "existing", Logging::Loggable(lci.outgoingProtobufExportConfig.servers.at(0).toString())));
a7f98e34
O
736 }
737 });
aa7929a3 738
b9fa43e0 739#ifdef HAVE_FSTRM
0b1bb97e 740 Lua->writeFunction("dnstapFrameStreamServer", [&lci](boost::variant<const std::string, const std::unordered_map<int, std::string>> servers, boost::optional<frameStreamOptions_t> vars) {
a7f98e34
O
741 if (!lci.frameStreamExportConfig.enabled) {
742
743 lci.frameStreamExportConfig.enabled = true;
744
745 try {
746 if (servers.type() == typeid(std::string)) {
747 auto server = boost::get<const std::string>(servers);
748 if (!boost::starts_with(server, "/")) {
749 ComboAddress parsecheck(server);
b9fa43e0 750 }
a7f98e34
O
751 lci.frameStreamExportConfig.servers.emplace_back(server);
752 }
753 else {
754 auto serversMap = boost::get<const std::unordered_map<int, std::string>>(servers);
755 for (const auto& serverPair : serversMap) {
756 lci.frameStreamExportConfig.servers.emplace_back(serverPair.second);
b9fa43e0 757 }
a7f98e34
O
758 }
759
760 parseFrameStreamOptions(vars, lci.frameStreamExportConfig);
b9fa43e0 761 }
a7f98e34 762 catch (std::exception& e) {
62b191dc
OM
763 SLOG(g_log << Logger::Error << "Error reading config for dnstap framestream logger: " << e.what() << endl,
764 lci.d_slog->error(Logr::Error, "Exception reading config for dnstap framestream logger", "exception", Logging::Loggable("std::exception")));
a7f98e34
O
765 }
766 catch (PDNSException& e) {
62b191dc
OM
767 SLOG(g_log << Logger::Error << "Error reading config for dnstap framestream logger: " << e.reason << endl,
768 lci.d_slog->error(Logr::Error, "Exception reading config for dnstap framestream logger", "exception", Logging::Loggable("PDNSException")));
b9fa43e0 769 }
a7f98e34
O
770 }
771 else {
62b191dc
OM
772 SLOG(g_log << Logger::Error << "Only one dnstapFrameStreamServer() directive can be configured, we already have " << lci.frameStreamExportConfig.servers.at(0) << endl,
773 lci.d_slog->info(Logr::Error, "Only one dnstapFrameStreamServer() directive can be configured", "existing", Logging::Loggable(lci.frameStreamExportConfig.servers.at(0))));
a7f98e34
O
774 }
775 });
9489e2b5
CHB
776 Lua->writeFunction("dnstapNODFrameStreamServer", [&lci](boost::variant<const std::string, const std::unordered_map<int, std::string>> servers, boost::optional<frameStreamOptions_t> vars) {
777 if (!lci.nodFrameStreamExportConfig.enabled) {
778 lci.nodFrameStreamExportConfig.enabled = true;
779
780 try {
781 if (servers.type() == typeid(std::string)) {
782 auto server = boost::get<const std::string>(servers);
783 if (!boost::starts_with(server, "/")) {
784 ComboAddress parsecheck(server);
785 }
786 lci.nodFrameStreamExportConfig.servers.emplace_back(server);
787 }
788 else {
789 auto serversMap = boost::get<const std::unordered_map<int, std::string>>(servers);
790 for (const auto& serverPair : serversMap) {
791 lci.nodFrameStreamExportConfig.servers.emplace_back(serverPair.second);
792 }
793 }
794
795 parseFrameStreamOptions(vars, lci.nodFrameStreamExportConfig);
796 }
797 catch (std::exception& e) {
798 SLOG(g_log << Logger::Error << "Error reading config for dnstap NOD framestream logger: " << e.what() << endl,
799 lci.d_slog->error(Logr::Error, "Exception reading config for dnstap NOD framestream logger", "exception", Logging::Loggable("std::exception")));
800 }
801 catch (PDNSException& e) {
802 SLOG(g_log << Logger::Error << "Error reading config for dnstap NOD framestream logger: " << e.reason << endl,
803 lci.d_slog->error(Logr::Error, "Exception reading config for dnstap NOD framestream logger", "exception", Logging::Loggable("PDNSException")));
804 }
805 }
806 else {
807 SLOG(g_log << Logger::Error << "Only one dnstapNODFrameStreamServer() directive can be configured, we already have " << lci.nodFrameStreamExportConfig.servers.at(0) << endl,
808 lci.d_slog->info(Logr::Error, "Only one dnstapNODFrameStreamServer() directive can be configured", "existing", Logging::Loggable(lci.nodFrameStreamExportConfig.servers.at(0))));
809 }
810 });
b9fa43e0
OM
811#endif /* HAVE_FSTRM */
812
1b47f291 813 Lua->writeFunction("addAllowedAdditionalQType", [&lci](int qtype, std::unordered_map<int, int> targetqtypes, boost::optional<std::map<std::string, int>> options) {
c21f8271
OM
814 switch (qtype) {
815 case QType::MX:
816 case QType::SRV:
817 case QType::SVCB:
818 case QType::HTTPS:
819 case QType::NAPTR:
820 break;
821 default:
f7631ff1
OM
822 SLOG(g_log << Logger::Error << "addAllowedAdditionalQType does not support " << QType(qtype).toString() << endl,
823 lci.d_slog->info(Logr::Error, "addAllowedAdditionalQType does not support this qtype", "qtype", Logging::Loggable(QType(qtype).toString())));
c21f8271
OM
824 return;
825 }
826
827 std::set<QType> targets;
828 for (const auto& t : targetqtypes) {
829 targets.emplace(QType(t.second));
830 }
831
832 AdditionalMode mode = AdditionalMode::CacheOnlyRequireAuth; // Always cheap and should be safe
833
834 if (options) {
835 if (const auto it = options->find("mode"); it != options->end()) {
1b47f291
OM
836 mode = static_cast<AdditionalMode>(it->second);
837 if (mode > AdditionalMode::ResolveDeferred) {
f7631ff1
OM
838 SLOG(g_log << Logger::Error << "addAllowedAdditionalQType: unknown mode " << it->second << endl,
839 lci.d_slog->info(Logr::Error, "addAllowedAdditionalQType: unknown mode", "mode", Logging::Loggable( it->second)));
c21f8271 840 }
c21f8271
OM
841 }
842 }
843 lci.allowAdditionalQTypes.insert_or_assign(qtype, pair(targets, mode));
844 });
845
f7631ff1 846 Lua->writeFunction("addProxyMapping", [&proxyMapping,&lci](const string& netmaskArg, const string& addressArg, boost::optional<std::vector<pair<int,std::string>>> smnStrings) {
e81063e5
OM
847 try {
848 Netmask netmask(netmaskArg);
849 ComboAddress address(addressArg);
20bfad6d
OM
850 boost::optional<SuffixMatchNode> smn;
851 if (smnStrings) {
852 smn = boost::make_optional(SuffixMatchNode{});
853 for (const auto& el : *smnStrings) {
854 smn->add(el.second);
855 }
856 }
857 proxyMapping.insert_or_assign(netmask, {address, smn});
e81063e5
OM
858 }
859 catch (std::exception& e) {
f7631ff1
OM
860 SLOG(g_log << Logger::Error << "Error processing addProxyMapping: " << e.what() << endl,
861 lci.d_slog->error(Logr::Error, e.what(), "Exception processing addProxyMapping", "exception", Logging::Loggable("std::exception")));
e81063e5
OM
862 }
863 catch (PDNSException& e) {
f7631ff1
OM
864 SLOG(g_log << Logger::Error << "Error processing addProxyMapping: " << e.reason << endl,
865 lci.d_slog->error(Logr::Error, e.reason, "Exception processing addProxyMapping", "exception", Logging::Loggable("PDNSException")));
e81063e5
OM
866 }
867 });
868
ad42489c 869 try {
0b1bb97e 870 Lua->executeCode(ifs);
d514bd03 871 g_luaconfs.setState(std::move(lci));
ad42489c 872 }
a7f98e34 873 catch (const LuaContext::ExecutionErrorException& e) {
f7631ff1
OM
874 SLOG(g_log << Logger::Error << "Unable to load Lua script from '" + fname + "': ",
875 lci.d_slog->error(Logr::Error, e.what(), "Unable to load Lua script", "file", Logging::Loggable(fname)));
2ac8ae89 876 try {
877 std::rethrow_if_nested(e);
a7f98e34
O
878 }
879 catch (const std::exception& exp) {
dd079764 880 // exp is the exception that was thrown from inside the lambda
f7631ff1
OM
881 SLOG(g_log << exp.what() << std::endl,
882 lci.d_slog->error(Logr::Error, exp.what(), "Exception loading Lua", "exception", Logging::Loggable("std::exception")));
2ac8ae89 883 }
a7f98e34 884 catch (const PDNSException& exp) {
dd079764 885 // exp is the exception that was thrown from inside the lambda
f7631ff1 886 SLOG(g_log << exp.reason << std::endl,
d15375fa
OM
887 lci.d_slog->error(Logr::Error, exp.reason, "Exception loading Lua", "exception", Logging::Loggable("PDNSException")));
888 }
2ac8ae89 889 throw;
2ac8ae89 890 }
a7f98e34 891 catch (std::exception& err) {
f7631ff1
OM
892 SLOG(g_log << Logger::Error << "Unable to load Lua script from '" + fname + "': " << err.what() << endl,
893 lci.d_slog->error(Logr::Error, err.what(), "Unable to load Lua script", "file", Logging::Loggable(fname), "exception", Logging::Loggable("std::exception")));
2ac8ae89 894 throw;
ad42489c 895 }
3e61e7f7 896}
6a99b9a4 897
e6ec15bf
RG
898void startLuaConfigDelayedThreads(const luaConfigDelayedThreads& delayedThreads, uint64_t generation)
899{
3d324e00 900 for (const auto& rpzPrimary : delayedThreads.rpzPrimaryThreads) {
e6ec15bf 901 try {
6b0048b8 902 // The get calls all return a value object here. That is essential, since we want copies so that RPZIXFRTracker gets values
4da91ffa 903 // with the proper lifetime.
3d324e00 904 std::thread t(RPZIXFRTracker, std::get<0>(rpzPrimary), std::get<1>(rpzPrimary), std::get<2>(rpzPrimary), std::get<3>(rpzPrimary), std::get<4>(rpzPrimary), std::get<5>(rpzPrimary), std::get<6>(rpzPrimary) * 1024 * 1024, std::get<7>(rpzPrimary), std::get<8>(rpzPrimary), std::get<9>(rpzPrimary), std::get<10>(rpzPrimary), std::get<11>(rpzPrimary), generation);
e6ec15bf
RG
905 t.detach();
906 }
a7f98e34 907 catch (const std::exception& e) {
62b191dc 908 SLOG(g_log << Logger::Error << "Problem starting RPZIXFRTracker thread: " << e.what() << endl,
84d24234 909 g_slog->withName("rpz")->error(Logr::Error, e.what(), "Exception starting RPZIXFRTracker thread", "exception", Logging::Loggable("std::exception")));
48defb61 910 exit(1);
e6ec15bf 911 }
a7f98e34 912 catch (const PDNSException& e) {
62b191dc 913 SLOG(g_log << Logger::Error << "Problem starting RPZIXFRTracker thread: " << e.reason << endl,
84d24234 914 g_slog->withName("rpz")->error(Logr::Error, e.reason, "Exception starting RPZIXFRTracker thread", "exception", Logging::Loggable("PDNSException")));
48defb61
OM
915 exit(1);
916 }
917 }
e6ec15bf 918}