]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/rec-lua-conf.cc
Merge pull request #8634 from rgacogne/auth-circle-unit-tests
[thirdparty/pdns.git] / pdns / rec-lua-conf.cc
1 #include "config.h"
2 #include "ext/luawrapper/include/LuaContext.hpp"
3
4 #include <fstream>
5 #include <thread>
6 #include "namespaces.hh"
7 #include "logger.hh"
8 #include "rec-lua-conf.hh"
9 #include "sortlist.hh"
10 #include "filterpo.hh"
11 #include "syncres.hh"
12 #include "rpzloader.hh"
13 #include "base64.hh"
14 #include "remote_logger.hh"
15 #include "validate.hh"
16 #include "validate-recursor.hh"
17 #include "root-dnssec.hh"
18
19 GlobalStateHolder<LuaConfigItems> g_luaconfs;
20
21 /* SO HOW DOES THIS WORK! AND PLEASE PAY ATTENTION!
22 This function can be called at any time. It is expected to overwrite all the contents
23 of LuaConfigItems, which is held in a GlobalStateHolder for RCU properties.
24
25 This function can be called again at a later date, so you must make sure that anything you
26 allow to be configured from here lives in g_luaconfs AND NOWHERE ELSE.
27
28 If someone loads an empty Lua file, the default LuaConfigItems struct MUST MAKE SENSE.
29
30 To make this easy on you, here is a LuaConfigItems constructor where you
31 can set sane defaults:
32 */
33
34 LuaConfigItems::LuaConfigItems()
35 {
36 DNSName root("."); // don't use g_rootdnsname here, it might not exist yet
37 for (const auto &dsRecord : rootDSs) {
38 auto ds=std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsRecord));
39 dsAnchors[root].insert(*ds);
40 }
41 }
42
43 /* DID YOU READ THE STORY ABOVE? */
44
45 template <typename C>
46 typename C::value_type::second_type constGet(const C& c, const std::string& name)
47 {
48 auto iter = c.find(name);
49 if(iter == c.end())
50 return 0;
51 return iter->second;
52 }
53
54 typedef std::unordered_map<std::string, boost::variant<bool, uint32_t, std::string > > rpzOptions_t;
55
56 static void parseRPZParameters(rpzOptions_t& have, std::string& polName, boost::optional<DNSFilterEngine::Policy>& defpol, bool& defpolOverrideLocal, uint32_t& maxTTL, size_t& zoneSizeHint)
57 {
58 if(have.count("policyName")) {
59 polName = boost::get<std::string>(have["policyName"]);
60 }
61 if(have.count("defpol")) {
62 defpol=DNSFilterEngine::Policy();
63 defpol->d_kind = (DNSFilterEngine::PolicyKind)boost::get<uint32_t>(have["defpol"]);
64 defpol->d_name = std::make_shared<std::string>(polName);
65 if(defpol->d_kind == DNSFilterEngine::PolicyKind::Custom) {
66 defpol->d_custom.push_back(DNSRecordContent::mastermake(QType::CNAME, QClass::IN,
67 boost::get<string>(have["defcontent"])));
68
69 if(have.count("defttl"))
70 defpol->d_ttl = static_cast<int32_t>(boost::get<uint32_t>(have["defttl"]));
71 else
72 defpol->d_ttl = -1; // get it from the zone
73 }
74
75 if (have.count("defpolOverrideLocalData")) {
76 defpolOverrideLocal = boost::get<bool>(have["defpolOverrideLocalData"]);
77 }
78 }
79 if(have.count("maxTTL")) {
80 maxTTL = boost::get<uint32_t>(have["maxTTL"]);
81 }
82 if(have.count("zoneSizeHint")) {
83 zoneSizeHint = static_cast<size_t>(boost::get<uint32_t>(have["zoneSizeHint"]));
84 }
85 }
86
87 #if HAVE_PROTOBUF
88 typedef std::unordered_map<std::string, boost::variant<bool, uint64_t, std::string, std::vector<std::pair<int,std::string> > > > protobufOptions_t;
89
90 static void parseProtobufOptions(boost::optional<protobufOptions_t> vars, ProtobufExportConfig& config)
91 {
92 if (!vars) {
93 return;
94 }
95
96 if (vars->count("timeout")) {
97 config.timeout = boost::get<uint64_t>((*vars)["timeout"]);
98 }
99
100 if (vars->count("maxQueuedEntries")) {
101 config.maxQueuedEntries = boost::get<uint64_t>((*vars)["maxQueuedEntries"]);
102 }
103
104 if (vars->count("reconnectWaitTime")) {
105 config.reconnectWaitTime = boost::get<uint64_t>((*vars)["reconnectWaitTime"]);
106 }
107
108 if (vars->count("asyncConnect")) {
109 config.asyncConnect = boost::get<bool>((*vars)["asyncConnect"]);
110 }
111
112 if (vars->count("taggedOnly")) {
113 config.taggedOnly = boost::get<bool>((*vars)["taggedOnly"]);
114 }
115
116 if (vars->count("logQueries")) {
117 config.logQueries = boost::get<bool>((*vars)["logQueries"]);
118 }
119
120 if (vars->count("logResponses")) {
121 config.logResponses = boost::get<bool>((*vars)["logResponses"]);
122 }
123
124 if (vars->count("exportTypes")) {
125 config.exportTypes.clear();
126
127 auto types = boost::get<std::vector<std::pair<int, std::string>>>((*vars)["exportTypes"]);
128 for (const auto& pair : types) {
129 const auto type = pair.second;
130 bool found = false;
131
132 for (const auto& entry : QType::names) {
133 if (entry.first == type) {
134 found = true;
135 config.exportTypes.insert(entry.second);
136 break;
137 }
138 }
139
140 if (!found) {
141 throw std::runtime_error("Unknown QType '" + type + "' in protobuf's export types");
142 }
143 }
144 }
145 }
146 #endif /* HAVE_PROTOBUF */
147
148 #ifdef HAVE_FSTRM
149 typedef std::unordered_map<std::string, boost::variant<bool, uint64_t, std::string, std::vector<std::pair<int,std::string> > > > frameStreamOptions_t;
150
151 static void parseFrameStreamOptions(boost::optional<frameStreamOptions_t> vars, FrameStreamExportConfig& config)
152 {
153 if (!vars) {
154 return;
155 }
156
157 if (vars->count("logQueries")) {
158 config.logQueries = boost::get<bool>((*vars)["logQueries"]);
159 }
160 if (vars->count("logResponses")) {
161 config.logResponses = boost::get<bool>((*vars)["logResponses"]);
162 }
163
164 if (vars->count("bufferHint")) {
165 config.bufferHint = boost::get<uint64_t>((*vars)["bufferHint"]);
166 }
167 if (vars->count("flushTimeout")) {
168 config.flushTimeout = boost::get<uint64_t>((*vars)["flushTimeout"]);
169 }
170 if (vars->count("inputQueueSize")) {
171 config.inputQueueSize = boost::get<uint64_t>((*vars)["inputQueueSize"]);
172 }
173 if (vars->count("outputQueueSize")) {
174 config.outputQueueSize = boost::get<uint64_t>((*vars)["outputQueueSize"]);
175 }
176 if (vars->count("queueNotifyThreshold")) {
177 config.queueNotifyThreshold = boost::get<uint64_t>((*vars)["queueNotifyThreshold"]);
178 }
179 if (vars->count("reopenInterval")) {
180 config.reopenInterval = boost::get<uint64_t>((*vars)["reopenInterval"]);
181 }
182 }
183 #endif /* HAVE_FSTRM */
184
185 void loadRecursorLuaConfig(const std::string& fname, luaConfigDelayedThreads& delayedThreads)
186 {
187 LuaConfigItems lci;
188
189 LuaContext Lua;
190 if(fname.empty())
191 return;
192 ifstream ifs(fname);
193 if(!ifs)
194 throw PDNSException("Cannot open file '"+fname+"': "+stringerror());
195
196 auto luaconfsLocal = g_luaconfs.getLocal();
197 lci.generation = luaconfsLocal->generation + 1;
198
199 // pdnslog here is compatible with pdnslog in lua-base4.cc.
200 Lua.writeFunction("pdnslog", [](const std::string& msg, boost::optional<int> loglevel) { g_log << (Logger::Urgency)loglevel.get_value_or(Logger::Warning) << msg<<endl; });
201 std::unordered_map<string, std::unordered_map<string, int>> pdns_table;
202 pdns_table["loglevels"] = std::unordered_map<string, int>{
203 {"Alert", LOG_ALERT},
204 {"Critical", LOG_CRIT},
205 {"Debug", LOG_DEBUG},
206 {"Emergency", LOG_EMERG},
207 {"Info", LOG_INFO},
208 {"Notice", LOG_NOTICE},
209 {"Warning", LOG_WARNING},
210 {"Error", LOG_ERR}
211 };
212 Lua.writeVariable("pdns", pdns_table);
213
214 Lua.writeFunction("clearSortlist", [&lci]() { lci.sortlist.clear(); });
215
216 /* we can get: "1.2.3.4"
217 {"1.2.3.4", "4.5.6.7"}
218 {"1.2.3.4", {"4.5.6.7", "8.9.10.11"}}
219 */
220
221 map<string,DNSFilterEngine::PolicyKind> pmap{
222 {"NoAction", DNSFilterEngine::PolicyKind::NoAction},
223 {"Drop", DNSFilterEngine::PolicyKind::Drop},
224 {"NXDOMAIN", DNSFilterEngine::PolicyKind::NXDOMAIN},
225 {"NODATA", DNSFilterEngine::PolicyKind::NODATA},
226 {"Truncate", DNSFilterEngine::PolicyKind::Truncate},
227 {"Custom", DNSFilterEngine::PolicyKind::Custom}
228 };
229 Lua.writeVariable("Policy", pmap);
230
231 Lua.writeFunction("rpzFile", [&lci](const string& filename, boost::optional<rpzOptions_t> options) {
232 try {
233 boost::optional<DNSFilterEngine::Policy> defpol;
234 bool defpolOverrideLocal = true;
235 std::string polName("rpzFile");
236 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
237 uint32_t maxTTL = std::numeric_limits<uint32_t>::max();
238 if(options) {
239 auto& have = *options;
240 size_t zoneSizeHint = 0;
241 parseRPZParameters(have, polName, defpol, defpolOverrideLocal, maxTTL, zoneSizeHint);
242 if (zoneSizeHint > 0) {
243 zone->reserve(zoneSizeHint);
244 }
245 }
246 g_log<<Logger::Warning<<"Loading RPZ from file '"<<filename<<"'"<<endl;
247 zone->setName(polName);
248 loadRPZFromFile(filename, zone, defpol, defpolOverrideLocal, maxTTL);
249 lci.dfe.addZone(zone);
250 g_log<<Logger::Warning<<"Done loading RPZ from file '"<<filename<<"'"<<endl;
251 }
252 catch(const std::exception& e) {
253 g_log<<Logger::Error<<"Unable to load RPZ zone from '"<<filename<<"': "<<e.what()<<endl;
254 }
255 });
256
257 Lua.writeFunction("rpzMaster", [&lci, &delayedThreads](const boost::variant<string, std::vector<std::pair<int, string> > >& masters_, const string& zoneName, boost::optional<rpzOptions_t> options) {
258
259 boost::optional<DNSFilterEngine::Policy> defpol;
260 bool defpolOverrideLocal = true;
261 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
262 TSIGTriplet tt;
263 uint32_t refresh=0;
264 size_t maxReceivedXFRMBytes = 0;
265 uint16_t axfrTimeout = 20;
266 uint32_t maxTTL = std::numeric_limits<uint32_t>::max();
267 ComboAddress localAddress;
268 std::vector<ComboAddress> masters;
269 if (masters_.type() == typeid(string)) {
270 masters.push_back(ComboAddress(boost::get<std::string>(masters_), 53));
271 }
272 else {
273 for (const auto& master : boost::get<std::vector<std::pair<int, std::string>>>(masters_)) {
274 masters.push_back(ComboAddress(master.second, 53));
275 }
276 }
277
278 size_t zoneIdx;
279 std::string dumpFile;
280 std::shared_ptr<SOARecordContent> sr = nullptr;
281
282 try {
283 std::string seedFile;
284 std::string polName(zoneName);
285
286 if (options) {
287 auto& have = *options;
288 size_t zoneSizeHint = 0;
289 parseRPZParameters(have, polName, defpol, defpolOverrideLocal, maxTTL, zoneSizeHint);
290 if (zoneSizeHint > 0) {
291 zone->reserve(zoneSizeHint);
292 }
293
294 if(have.count("tsigname")) {
295 tt.name=DNSName(toLower(boost::get<string>(have["tsigname"])));
296 tt.algo=DNSName(toLower(boost::get<string>(have[ "tsigalgo"])));
297 if(B64Decode(boost::get<string>(have[ "tsigsecret"]), tt.secret))
298 throw std::runtime_error("TSIG secret is not valid Base-64 encoded");
299 }
300
301 if(have.count("refresh")) {
302 refresh = boost::get<uint32_t>(have["refresh"]);
303 if (refresh == 0) {
304 g_log<<Logger::Warning<<"rpzMaster refresh value of 0 ignored"<<endl;
305 }
306 }
307
308 if(have.count("maxReceivedMBytes")) {
309 maxReceivedXFRMBytes = static_cast<size_t>(boost::get<uint32_t>(have["maxReceivedMBytes"]));
310 }
311
312 if(have.count("localAddress")) {
313 localAddress = ComboAddress(boost::get<string>(have["localAddress"]));
314 }
315
316 if(have.count("axfrTimeout")) {
317 axfrTimeout = static_cast<uint16_t>(boost::get<uint32_t>(have["axfrTimeout"]));
318 }
319
320 if(have.count("seedFile")) {
321 seedFile = boost::get<std::string>(have["seedFile"]);
322 }
323
324 if(have.count("dumpFile")) {
325 dumpFile = boost::get<std::string>(have["dumpFile"]);
326 }
327 }
328
329 if (localAddress != ComboAddress()) {
330 // We were passed a localAddress, check if its AF matches the masters'
331 for (const auto& master : masters) {
332 if (localAddress.sin4.sin_family != master.sin4.sin_family) {
333 throw PDNSException("Master address("+master.toString()+") is not of the same Address Family as the local address ("+localAddress.toString()+").");
334 }
335 }
336 }
337
338 DNSName domain(zoneName);
339 zone->setDomain(domain);
340 zone->setName(polName);
341 zoneIdx = lci.dfe.addZone(zone);
342
343 if (!seedFile.empty()) {
344 g_log<<Logger::Info<<"Pre-loading RPZ zone "<<zoneName<<" from seed file '"<<seedFile<<"'"<<endl;
345 try {
346 sr = loadRPZFromFile(seedFile, zone, defpol, defpolOverrideLocal, maxTTL);
347
348 if (zone->getDomain() != domain) {
349 throw PDNSException("The RPZ zone " + zoneName + " loaded from the seed file (" + zone->getDomain().toString() + ") does not match the one passed in parameter (" + domain.toString() + ")");
350 }
351
352 if (sr == nullptr) {
353 throw PDNSException("The RPZ zone " + zoneName + " loaded from the seed file (" + zone->getDomain().toString() + ") has no SOA record");
354 }
355 }
356 catch(const std::exception& e) {
357 g_log<<Logger::Warning<<"Unable to pre-load RPZ zone "<<zoneName<<" from seed file '"<<seedFile<<"': "<<e.what()<<endl;
358 }
359 }
360 }
361 catch(const std::exception& e) {
362 g_log<<Logger::Error<<"Problem configuring 'rpzMaster': "<<e.what()<<endl;
363 exit(1); // FIXME proper exit code?
364 }
365 catch(const PDNSException& e) {
366 g_log<<Logger::Error<<"Problem configuring 'rpzMaster': "<<e.reason<<endl;
367 exit(1); // FIXME proper exit code?
368 }
369
370 delayedThreads.rpzMasterThreads.push_back(std::make_tuple(masters, defpol, defpolOverrideLocal, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes, localAddress, axfrTimeout, refresh, sr, dumpFile));
371 });
372
373 typedef vector<pair<int,boost::variant<string, vector<pair<int, string> > > > > argvec_t;
374 Lua.writeFunction("addSortList",
375 [&lci](const std::string& formask_,
376 const boost::variant<string, argvec_t>& masks,
377 boost::optional<int> order_)
378 {
379 try {
380 Netmask formask(formask_);
381 int order = order_ ? (*order_) : lci.sortlist.getMaxOrder(formask)+1;
382 if(auto str = boost::get<string>(&masks))
383 lci.sortlist.addEntry(formask, Netmask(*str), order);
384 else {
385
386 auto vec = boost::get<argvec_t>(&masks);
387 for(const auto& e : *vec) {
388 if(auto s = boost::get<string>(&e.second)) {
389 lci.sortlist.addEntry(formask, Netmask(*s), order);
390 }
391 else {
392 const auto& v =boost::get<vector<pair<int, string> > >(e.second);
393 for(const auto& entry : v)
394 lci.sortlist.addEntry(formask, Netmask(entry.second), order);
395 }
396 ++order;
397 }
398 }
399 }
400 catch(std::exception& e) {
401 g_log<<Logger::Error<<"Error in addSortList: "<<e.what()<<endl;
402 }
403 });
404
405 Lua.writeFunction("addTA", [&lci](const std::string& who, const std::string& what) {
406 warnIfDNSSECDisabled("Warning: adding Trust Anchor for DNSSEC (addTA), but dnssec is set to 'off'!");
407 DNSName zone(who);
408 auto ds = std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(what));
409 lci.dsAnchors[zone].insert(*ds);
410 });
411
412 Lua.writeFunction("clearTA", [&lci](boost::optional<string> who) {
413 warnIfDNSSECDisabled("Warning: removing Trust Anchor for DNSSEC (clearTA), but dnssec is set to 'off'!");
414 if(who)
415 lci.dsAnchors.erase(DNSName(*who));
416 else
417 lci.dsAnchors.clear();
418 });
419
420 /* Remove in 4.3 */
421 Lua.writeFunction("addDS", [&lci](const std::string& who, const std::string& what) {
422 warnIfDNSSECDisabled("Warning: adding Trust Anchor for DNSSEC (addDS), but dnssec is set to 'off'!");
423 g_log<<Logger::Warning<<"addDS is deprecated and will be removed in the future, switch to addTA"<<endl;
424 DNSName zone(who);
425 auto ds = std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(what));
426 lci.dsAnchors[zone].insert(*ds);
427 });
428
429 /* Remove in 4.3 */
430 Lua.writeFunction("clearDS", [&lci](boost::optional<string> who) {
431 g_log<<Logger::Warning<<"clearDS is deprecated and will be removed in the future, switch to clearTA"<<endl;
432 warnIfDNSSECDisabled("Warning: removing Trust Anchor for DNSSEC (clearDS), but dnssec is set to 'off'!");
433 if(who)
434 lci.dsAnchors.erase(DNSName(*who));
435 else
436 lci.dsAnchors.clear();
437 });
438
439 Lua.writeFunction("addNTA", [&lci](const std::string& who, const boost::optional<std::string> why) {
440 warnIfDNSSECDisabled("Warning: adding Negative Trust Anchor for DNSSEC (addNTA), but dnssec is set to 'off'!");
441 if(why)
442 lci.negAnchors[DNSName(who)] = static_cast<string>(*why);
443 else
444 lci.negAnchors[DNSName(who)] = "";
445 });
446
447 Lua.writeFunction("clearNTA", [&lci](boost::optional<string> who) {
448 warnIfDNSSECDisabled("Warning: removing Negative Trust Anchor for DNSSEC (clearNTA), but dnssec is set to 'off'!");
449 if(who)
450 lci.negAnchors.erase(DNSName(*who));
451 else
452 lci.negAnchors.clear();
453 });
454
455 Lua.writeFunction("readTrustAnchorsFromFile", [&lci](const std::string& fnamearg, const boost::optional<uint32_t> interval) {
456 uint32_t realInterval = 24;
457 if (interval) {
458 realInterval = static_cast<uint32_t>(*interval);
459 }
460 warnIfDNSSECDisabled("Warning: reading Trust Anchors from file (readTrustAnchorsFromFile), but dnssec is set to 'off'!");
461 lci.trustAnchorFileInfo.fname = fnamearg;
462 lci.trustAnchorFileInfo.interval = realInterval;
463 updateTrustAnchorsFromFile(fnamearg, lci.dsAnchors);
464 });
465
466 #if HAVE_PROTOBUF
467 Lua.writeFunction("setProtobufMasks", [&lci](const uint8_t maskV4, uint8_t maskV6) {
468 lci.protobufMaskV4 = maskV4;
469 lci.protobufMaskV6 = maskV6;
470 });
471
472 Lua.writeFunction("protobufServer", [&lci](boost::variant<const std::string, const std::unordered_map<int, std::string>> servers, boost::optional<protobufOptions_t> vars) {
473 if (!lci.protobufExportConfig.enabled) {
474
475 lci.protobufExportConfig.enabled = true;
476
477 try {
478 if (servers.type() == typeid(std::string)) {
479 auto server = boost::get<const std::string>(servers);
480
481 lci.protobufExportConfig.servers.emplace_back(server);
482 }
483 else {
484 auto serversMap = boost::get<const std::unordered_map<int,std::string>>(servers);
485 for (const auto& serverPair : serversMap) {
486 lci.protobufExportConfig.servers.emplace_back(serverPair.second);
487 }
488 }
489
490 parseProtobufOptions(vars, lci.protobufExportConfig);
491 }
492 catch(std::exception& e) {
493 g_log<<Logger::Error<<"Error while adding protobuf logger: "<<e.what()<<endl;
494 }
495 catch(PDNSException& e) {
496 g_log<<Logger::Error<<"Error while adding protobuf logger: "<<e.reason<<endl;
497 }
498 }
499 else {
500 g_log<<Logger::Error<<"Only one protobufServer() directive can be configured, we already have "<<lci.protobufExportConfig.servers.at(0).toString()<<endl;
501 }
502 });
503
504 Lua.writeFunction("outgoingProtobufServer", [&lci](boost::variant<const std::string, const std::unordered_map<int, std::string>> servers, boost::optional<protobufOptions_t> vars) {
505 if (!lci.outgoingProtobufExportConfig.enabled) {
506
507 lci.outgoingProtobufExportConfig.enabled = true;
508
509 try {
510 if (servers.type() == typeid(std::string)) {
511 auto server = boost::get<const std::string>(servers);
512
513 lci.outgoingProtobufExportConfig.servers.emplace_back(server);
514 }
515 else {
516 auto serversMap = boost::get<const std::unordered_map<int,std::string>>(servers);
517 for (const auto& serverPair : serversMap) {
518 lci.outgoingProtobufExportConfig.servers.emplace_back(serverPair.second);
519 }
520 }
521
522 parseProtobufOptions(vars, lci.outgoingProtobufExportConfig);
523 }
524 catch(std::exception& e) {
525 g_log<<Logger::Error<<"Error while starting outgoing protobuf logger: "<<e.what()<<endl;
526 }
527 catch(PDNSException& e) {
528 g_log<<Logger::Error<<"Error while starting outgoing protobuf logger: "<<e.reason<<endl;
529 }
530 }
531 else {
532 g_log<<Logger::Error<<"Only one outgoingProtobufServer() directive can be configured, we already have "<<lci.outgoingProtobufExportConfig.servers.at(0).toString()<<endl;
533 }
534 });
535 #endif
536
537 #ifdef HAVE_FSTRM
538 Lua.writeFunction("dnstapFrameStreamServer", [&lci](boost::variant<const std::string, const std::unordered_map<int, std::string>> servers, boost::optional<frameStreamOptions_t> vars) {
539 if (!lci.frameStreamExportConfig.enabled) {
540
541 lci.frameStreamExportConfig.enabled = true;
542
543 try {
544 if (servers.type() == typeid(std::string)) {
545 auto server = boost::get<const std::string>(servers);
546 if (!boost::starts_with(server, "/")) {
547 ComboAddress parsecheck(server);
548 }
549 lci.frameStreamExportConfig.servers.emplace_back(server);
550 }
551 else {
552 auto serversMap = boost::get<const std::unordered_map<int,std::string>>(servers);
553 for (const auto& serverPair : serversMap) {
554 lci.frameStreamExportConfig.servers.emplace_back(serverPair.second);
555 }
556 }
557
558 parseFrameStreamOptions(vars, lci.frameStreamExportConfig);
559 }
560 catch(std::exception& e) {
561 g_log<<Logger::Error<<"Error reading config for dnstap framestream logger: "<<e.what()<<endl;
562 }
563 catch(PDNSException& e) {
564 g_log<<Logger::Error<<"Error reading config for dnstap framestream logger: "<<e.reason<<endl;
565 }
566 }
567 else {
568 g_log<<Logger::Error<<"Only one dnstapFrameStreamServer() directive can be configured, we already have "<<lci.frameStreamExportConfig.servers.at(0)<<endl;
569 }
570 });
571 #endif /* HAVE_FSTRM */
572
573 try {
574 Lua.executeCode(ifs);
575 g_luaconfs.setState(std::move(lci));
576 }
577 catch(const LuaContext::ExecutionErrorException& e) {
578 g_log<<Logger::Error<<"Unable to load Lua script from '"+fname+"': ";
579 try {
580 std::rethrow_if_nested(e);
581 } catch(const std::exception& exp) {
582 // exp is the exception that was thrown from inside the lambda
583 g_log << exp.what() << std::endl;
584 }
585 catch(const PDNSException& exp) {
586 // exp is the exception that was thrown from inside the lambda
587 g_log << exp.reason << std::endl;
588 }
589 throw;
590
591 }
592 catch(std::exception& err) {
593 g_log<<Logger::Error<<"Unable to load Lua script from '"+fname+"': "<<err.what()<<endl;
594 throw;
595 }
596
597 }
598
599 void startLuaConfigDelayedThreads(const luaConfigDelayedThreads& delayedThreads, uint64_t generation)
600 {
601 for (const auto& rpzMaster : delayedThreads.rpzMasterThreads) {
602 try {
603 std::thread t(RPZIXFRTracker, std::get<0>(rpzMaster), std::get<1>(rpzMaster), std::get<2>(rpzMaster), std::get<3>(rpzMaster), std::get<4>(rpzMaster), std::get<5>(rpzMaster), std::get<6>(rpzMaster) * 1024 * 1024, std::get<7>(rpzMaster), std::get<8>(rpzMaster), std::get<9>(rpzMaster), std::get<10>(rpzMaster), std::get<11>(rpzMaster), generation);
604 t.detach();
605 }
606 catch(const std::exception& e) {
607 g_log<<Logger::Error<<"Problem starting RPZIXFRTracker thread: "<<e.what()<<endl;
608 exit(1); // FIXME proper exit code?
609 }
610 catch(const PDNSException& e) {
611 g_log<<Logger::Error<<"Problem starting RPZIXFRTracker thread: "<<e.reason<<endl;
612 exit(1); // FIXME proper exit code?
613 }
614 }
615 }