]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/rec-lua-conf.cc
Avoid throwing an exception in Logger::log().
[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, std::vector<std::pair<int, 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, std::unordered_set<std::string>& tags)
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->setName(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 if (have.count("tags")) {
86 const auto tagsTable = boost::get<std::vector<std::pair<int, std::string>>>(have["tags"]);
87 for (const auto& tag : tagsTable) {
88 tags.insert(tag.second);
89 }
90 }
91 }
92
93 #if HAVE_PROTOBUF
94 typedef std::unordered_map<std::string, boost::variant<bool, uint64_t, std::string, std::vector<std::pair<int,std::string> > > > protobufOptions_t;
95
96 static void parseProtobufOptions(boost::optional<protobufOptions_t> vars, ProtobufExportConfig& config)
97 {
98 if (!vars) {
99 return;
100 }
101
102 if (vars->count("timeout")) {
103 config.timeout = boost::get<uint64_t>((*vars)["timeout"]);
104 }
105
106 if (vars->count("maxQueuedEntries")) {
107 config.maxQueuedEntries = boost::get<uint64_t>((*vars)["maxQueuedEntries"]);
108 }
109
110 if (vars->count("reconnectWaitTime")) {
111 config.reconnectWaitTime = boost::get<uint64_t>((*vars)["reconnectWaitTime"]);
112 }
113
114 if (vars->count("asyncConnect")) {
115 config.asyncConnect = boost::get<bool>((*vars)["asyncConnect"]);
116 }
117
118 if (vars->count("taggedOnly")) {
119 config.taggedOnly = boost::get<bool>((*vars)["taggedOnly"]);
120 }
121
122 if (vars->count("logQueries")) {
123 config.logQueries = boost::get<bool>((*vars)["logQueries"]);
124 }
125
126 if (vars->count("logResponses")) {
127 config.logResponses = boost::get<bool>((*vars)["logResponses"]);
128 }
129
130 if (vars->count("exportTypes")) {
131 config.exportTypes.clear();
132
133 auto types = boost::get<std::vector<std::pair<int, std::string>>>((*vars)["exportTypes"]);
134 for (const auto& pair : types) {
135 const auto type = pair.second;
136 bool found = false;
137
138 for (const auto& entry : QType::names) {
139 if (entry.first == type) {
140 found = true;
141 config.exportTypes.insert(entry.second);
142 break;
143 }
144 }
145
146 if (!found) {
147 throw std::runtime_error("Unknown QType '" + type + "' in protobuf's export types");
148 }
149 }
150 }
151 }
152 #endif /* HAVE_PROTOBUF */
153
154 #ifdef HAVE_FSTRM
155 typedef std::unordered_map<std::string, boost::variant<bool, uint64_t, std::string, std::vector<std::pair<int,std::string> > > > frameStreamOptions_t;
156
157 static void parseFrameStreamOptions(boost::optional<frameStreamOptions_t> vars, FrameStreamExportConfig& config)
158 {
159 if (!vars) {
160 return;
161 }
162
163 if (vars->count("logQueries")) {
164 config.logQueries = boost::get<bool>((*vars)["logQueries"]);
165 }
166 if (vars->count("logResponses")) {
167 config.logResponses = boost::get<bool>((*vars)["logResponses"]);
168 }
169
170 if (vars->count("bufferHint")) {
171 config.bufferHint = boost::get<uint64_t>((*vars)["bufferHint"]);
172 }
173 if (vars->count("flushTimeout")) {
174 config.flushTimeout = boost::get<uint64_t>((*vars)["flushTimeout"]);
175 }
176 if (vars->count("inputQueueSize")) {
177 config.inputQueueSize = boost::get<uint64_t>((*vars)["inputQueueSize"]);
178 }
179 if (vars->count("outputQueueSize")) {
180 config.outputQueueSize = boost::get<uint64_t>((*vars)["outputQueueSize"]);
181 }
182 if (vars->count("queueNotifyThreshold")) {
183 config.queueNotifyThreshold = boost::get<uint64_t>((*vars)["queueNotifyThreshold"]);
184 }
185 if (vars->count("reopenInterval")) {
186 config.reopenInterval = boost::get<uint64_t>((*vars)["reopenInterval"]);
187 }
188 }
189 #endif /* HAVE_FSTRM */
190
191 void loadRecursorLuaConfig(const std::string& fname, luaConfigDelayedThreads& delayedThreads)
192 {
193 LuaConfigItems lci;
194
195 LuaContext Lua;
196 if(fname.empty())
197 return;
198 ifstream ifs(fname);
199 if(!ifs)
200 throw PDNSException("Cannot open file '"+fname+"': "+stringerror());
201
202 auto luaconfsLocal = g_luaconfs.getLocal();
203 lci.generation = luaconfsLocal->generation + 1;
204
205 // pdnslog here is compatible with pdnslog in lua-base4.cc.
206 Lua.writeFunction("pdnslog", [](const std::string& msg, boost::optional<int> loglevel) { g_log << (Logger::Urgency)loglevel.get_value_or(Logger::Warning) << msg<<endl; });
207 std::unordered_map<string, std::unordered_map<string, int>> pdns_table;
208 pdns_table["loglevels"] = std::unordered_map<string, int>{
209 {"Alert", LOG_ALERT},
210 {"Critical", LOG_CRIT},
211 {"Debug", LOG_DEBUG},
212 {"Emergency", LOG_EMERG},
213 {"Info", LOG_INFO},
214 {"Notice", LOG_NOTICE},
215 {"Warning", LOG_WARNING},
216 {"Error", LOG_ERR}
217 };
218 Lua.writeVariable("pdns", pdns_table);
219
220 Lua.writeFunction("clearSortlist", [&lci]() { lci.sortlist.clear(); });
221
222 /* we can get: "1.2.3.4"
223 {"1.2.3.4", "4.5.6.7"}
224 {"1.2.3.4", {"4.5.6.7", "8.9.10.11"}}
225 */
226
227 map<string,DNSFilterEngine::PolicyKind> pmap{
228 {"NoAction", DNSFilterEngine::PolicyKind::NoAction},
229 {"Drop", DNSFilterEngine::PolicyKind::Drop},
230 {"NXDOMAIN", DNSFilterEngine::PolicyKind::NXDOMAIN},
231 {"NODATA", DNSFilterEngine::PolicyKind::NODATA},
232 {"Truncate", DNSFilterEngine::PolicyKind::Truncate},
233 {"Custom", DNSFilterEngine::PolicyKind::Custom}
234 };
235 Lua.writeVariable("Policy", pmap);
236
237 Lua.writeFunction("rpzFile", [&lci](const string& filename, boost::optional<rpzOptions_t> options) {
238 try {
239 boost::optional<DNSFilterEngine::Policy> defpol;
240 bool defpolOverrideLocal = true;
241 std::string polName("rpzFile");
242 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
243 uint32_t maxTTL = std::numeric_limits<uint32_t>::max();
244 if(options) {
245 auto& have = *options;
246 size_t zoneSizeHint = 0;
247 std::unordered_set<std::string> tags;
248 parseRPZParameters(have, polName, defpol, defpolOverrideLocal, maxTTL, zoneSizeHint, tags);
249 if (zoneSizeHint > 0) {
250 zone->reserve(zoneSizeHint);
251 }
252 zone->setTags(std::move(tags));
253 }
254 g_log<<Logger::Warning<<"Loading RPZ from file '"<<filename<<"'"<<endl;
255 zone->setName(polName);
256 loadRPZFromFile(filename, zone, defpol, defpolOverrideLocal, maxTTL);
257 lci.dfe.addZone(zone);
258 g_log<<Logger::Warning<<"Done loading RPZ from file '"<<filename<<"'"<<endl;
259 }
260 catch(const std::exception& e) {
261 g_log<<Logger::Error<<"Unable to load RPZ zone from '"<<filename<<"': "<<e.what()<<endl;
262 }
263 });
264
265 Lua.writeFunction("rpzMaster", [&lci, &delayedThreads](const boost::variant<string, std::vector<std::pair<int, string> > >& masters_, const string& zoneName, boost::optional<rpzOptions_t> options) {
266
267 boost::optional<DNSFilterEngine::Policy> defpol;
268 bool defpolOverrideLocal = true;
269 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
270 TSIGTriplet tt;
271 uint32_t refresh=0;
272 size_t maxReceivedXFRMBytes = 0;
273 uint16_t axfrTimeout = 20;
274 uint32_t maxTTL = std::numeric_limits<uint32_t>::max();
275 ComboAddress localAddress;
276 std::vector<ComboAddress> masters;
277 if (masters_.type() == typeid(string)) {
278 masters.push_back(ComboAddress(boost::get<std::string>(masters_), 53));
279 }
280 else {
281 for (const auto& master : boost::get<std::vector<std::pair<int, std::string>>>(masters_)) {
282 masters.push_back(ComboAddress(master.second, 53));
283 }
284 }
285
286 size_t zoneIdx;
287 std::string dumpFile;
288 std::shared_ptr<SOARecordContent> sr = nullptr;
289
290 try {
291 std::string seedFile;
292 std::string polName(zoneName);
293
294 if (options) {
295 auto& have = *options;
296 size_t zoneSizeHint = 0;
297 std::unordered_set<std::string> tags;
298 parseRPZParameters(have, polName, defpol, defpolOverrideLocal, maxTTL, zoneSizeHint, tags);
299 if (zoneSizeHint > 0) {
300 zone->reserve(zoneSizeHint);
301 }
302 zone->setTags(std::move(tags));
303
304 if(have.count("tsigname")) {
305 tt.name=DNSName(toLower(boost::get<string>(have["tsigname"])));
306 tt.algo=DNSName(toLower(boost::get<string>(have[ "tsigalgo"])));
307 if(B64Decode(boost::get<string>(have[ "tsigsecret"]), tt.secret))
308 throw std::runtime_error("TSIG secret is not valid Base-64 encoded");
309 }
310
311 if(have.count("refresh")) {
312 refresh = boost::get<uint32_t>(have["refresh"]);
313 if (refresh == 0) {
314 g_log<<Logger::Warning<<"rpzMaster refresh value of 0 ignored"<<endl;
315 }
316 }
317
318 if(have.count("maxReceivedMBytes")) {
319 maxReceivedXFRMBytes = static_cast<size_t>(boost::get<uint32_t>(have["maxReceivedMBytes"]));
320 }
321
322 if(have.count("localAddress")) {
323 localAddress = ComboAddress(boost::get<string>(have["localAddress"]));
324 }
325
326 if(have.count("axfrTimeout")) {
327 axfrTimeout = static_cast<uint16_t>(boost::get<uint32_t>(have["axfrTimeout"]));
328 }
329
330 if(have.count("seedFile")) {
331 seedFile = boost::get<std::string>(have["seedFile"]);
332 }
333
334 if(have.count("dumpFile")) {
335 dumpFile = boost::get<std::string>(have["dumpFile"]);
336 }
337 }
338
339 if (localAddress != ComboAddress()) {
340 // We were passed a localAddress, check if its AF matches the masters'
341 for (const auto& master : masters) {
342 if (localAddress.sin4.sin_family != master.sin4.sin_family) {
343 throw PDNSException("Master address("+master.toString()+") is not of the same Address Family as the local address ("+localAddress.toString()+").");
344 }
345 }
346 }
347
348 DNSName domain(zoneName);
349 zone->setDomain(domain);
350 zone->setName(polName);
351 zoneIdx = lci.dfe.addZone(zone);
352
353 if (!seedFile.empty()) {
354 g_log<<Logger::Info<<"Pre-loading RPZ zone "<<zoneName<<" from seed file '"<<seedFile<<"'"<<endl;
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 }
366 catch(const std::exception& e) {
367 g_log<<Logger::Warning<<"Unable to pre-load RPZ zone "<<zoneName<<" from seed file '"<<seedFile<<"': "<<e.what()<<endl;
368 }
369 }
370 }
371 catch(const std::exception& e) {
372 g_log<<Logger::Error<<"Problem configuring 'rpzMaster': "<<e.what()<<endl;
373 exit(1); // FIXME proper exit code?
374 }
375 catch(const PDNSException& e) {
376 g_log<<Logger::Error<<"Problem configuring 'rpzMaster': "<<e.reason<<endl;
377 exit(1); // FIXME proper exit code?
378 }
379
380 delayedThreads.rpzMasterThreads.push_back(std::make_tuple(masters, defpol, defpolOverrideLocal, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes, localAddress, axfrTimeout, refresh, sr, dumpFile));
381 });
382
383 typedef vector<pair<int,boost::variant<string, vector<pair<int, string> > > > > argvec_t;
384 Lua.writeFunction("addSortList",
385 [&lci](const std::string& formask_,
386 const boost::variant<string, argvec_t>& masks,
387 boost::optional<int> order_)
388 {
389 try {
390 Netmask formask(formask_);
391 int order = order_ ? (*order_) : lci.sortlist.getMaxOrder(formask)+1;
392 if(auto str = boost::get<string>(&masks))
393 lci.sortlist.addEntry(formask, Netmask(*str), order);
394 else {
395
396 auto vec = boost::get<argvec_t>(&masks);
397 for(const auto& e : *vec) {
398 if(auto s = boost::get<string>(&e.second)) {
399 lci.sortlist.addEntry(formask, Netmask(*s), order);
400 }
401 else {
402 const auto& v =boost::get<vector<pair<int, string> > >(e.second);
403 for(const auto& entry : v)
404 lci.sortlist.addEntry(formask, Netmask(entry.second), order);
405 }
406 ++order;
407 }
408 }
409 }
410 catch(std::exception& e) {
411 g_log<<Logger::Error<<"Error in addSortList: "<<e.what()<<endl;
412 }
413 });
414
415 Lua.writeFunction("addTA", [&lci](const std::string& who, const std::string& what) {
416 warnIfDNSSECDisabled("Warning: adding Trust Anchor for DNSSEC (addTA), but dnssec is set to 'off'!");
417 DNSName zone(who);
418 auto ds = std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(what));
419 lci.dsAnchors[zone].insert(*ds);
420 });
421
422 Lua.writeFunction("clearTA", [&lci](boost::optional<string> who) {
423 warnIfDNSSECDisabled("Warning: removing Trust Anchor for DNSSEC (clearTA), but dnssec is set to 'off'!");
424 if(who)
425 lci.dsAnchors.erase(DNSName(*who));
426 else
427 lci.dsAnchors.clear();
428 });
429
430 /* Remove in 4.3 */
431 Lua.writeFunction("addDS", [&lci](const std::string& who, const std::string& what) {
432 warnIfDNSSECDisabled("Warning: adding Trust Anchor for DNSSEC (addDS), but dnssec is set to 'off'!");
433 g_log<<Logger::Warning<<"addDS is deprecated and will be removed in the future, switch to addTA"<<endl;
434 DNSName zone(who);
435 auto ds = std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(what));
436 lci.dsAnchors[zone].insert(*ds);
437 });
438
439 /* Remove in 4.3 */
440 Lua.writeFunction("clearDS", [&lci](boost::optional<string> who) {
441 g_log<<Logger::Warning<<"clearDS is deprecated and will be removed in the future, switch to clearTA"<<endl;
442 warnIfDNSSECDisabled("Warning: removing Trust Anchor for DNSSEC (clearDS), but dnssec is set to 'off'!");
443 if(who)
444 lci.dsAnchors.erase(DNSName(*who));
445 else
446 lci.dsAnchors.clear();
447 });
448
449 Lua.writeFunction("addNTA", [&lci](const std::string& who, const boost::optional<std::string> why) {
450 warnIfDNSSECDisabled("Warning: adding Negative Trust Anchor for DNSSEC (addNTA), but dnssec is set to 'off'!");
451 if(why)
452 lci.negAnchors[DNSName(who)] = static_cast<string>(*why);
453 else
454 lci.negAnchors[DNSName(who)] = "";
455 });
456
457 Lua.writeFunction("clearNTA", [&lci](boost::optional<string> who) {
458 warnIfDNSSECDisabled("Warning: removing Negative Trust Anchor for DNSSEC (clearNTA), but dnssec is set to 'off'!");
459 if(who)
460 lci.negAnchors.erase(DNSName(*who));
461 else
462 lci.negAnchors.clear();
463 });
464
465 Lua.writeFunction("readTrustAnchorsFromFile", [&lci](const std::string& fnamearg, const boost::optional<uint32_t> interval) {
466 uint32_t realInterval = 24;
467 if (interval) {
468 realInterval = static_cast<uint32_t>(*interval);
469 }
470 warnIfDNSSECDisabled("Warning: reading Trust Anchors from file (readTrustAnchorsFromFile), but dnssec is set to 'off'!");
471 lci.trustAnchorFileInfo.fname = fnamearg;
472 lci.trustAnchorFileInfo.interval = realInterval;
473 updateTrustAnchorsFromFile(fnamearg, lci.dsAnchors);
474 });
475
476 #if HAVE_PROTOBUF
477 Lua.writeFunction("setProtobufMasks", [&lci](const uint8_t maskV4, uint8_t maskV6) {
478 lci.protobufMaskV4 = maskV4;
479 lci.protobufMaskV6 = maskV6;
480 });
481
482 Lua.writeFunction("protobufServer", [&lci](boost::variant<const std::string, const std::unordered_map<int, std::string>> servers, boost::optional<protobufOptions_t> vars) {
483 if (!lci.protobufExportConfig.enabled) {
484
485 lci.protobufExportConfig.enabled = true;
486
487 try {
488 if (servers.type() == typeid(std::string)) {
489 auto server = boost::get<const std::string>(servers);
490
491 lci.protobufExportConfig.servers.emplace_back(server);
492 }
493 else {
494 auto serversMap = boost::get<const std::unordered_map<int,std::string>>(servers);
495 for (const auto& serverPair : serversMap) {
496 lci.protobufExportConfig.servers.emplace_back(serverPair.second);
497 }
498 }
499
500 parseProtobufOptions(vars, lci.protobufExportConfig);
501 }
502 catch(std::exception& e) {
503 g_log<<Logger::Error<<"Error while adding protobuf logger: "<<e.what()<<endl;
504 }
505 catch(PDNSException& e) {
506 g_log<<Logger::Error<<"Error while adding protobuf logger: "<<e.reason<<endl;
507 }
508 }
509 else {
510 g_log<<Logger::Error<<"Only one protobufServer() directive can be configured, we already have "<<lci.protobufExportConfig.servers.at(0).toString()<<endl;
511 }
512 });
513
514 Lua.writeFunction("outgoingProtobufServer", [&lci](boost::variant<const std::string, const std::unordered_map<int, std::string>> servers, boost::optional<protobufOptions_t> vars) {
515 if (!lci.outgoingProtobufExportConfig.enabled) {
516
517 lci.outgoingProtobufExportConfig.enabled = true;
518
519 try {
520 if (servers.type() == typeid(std::string)) {
521 auto server = boost::get<const std::string>(servers);
522
523 lci.outgoingProtobufExportConfig.servers.emplace_back(server);
524 }
525 else {
526 auto serversMap = boost::get<const std::unordered_map<int,std::string>>(servers);
527 for (const auto& serverPair : serversMap) {
528 lci.outgoingProtobufExportConfig.servers.emplace_back(serverPair.second);
529 }
530 }
531
532 parseProtobufOptions(vars, lci.outgoingProtobufExportConfig);
533 }
534 catch(std::exception& e) {
535 g_log<<Logger::Error<<"Error while starting outgoing protobuf logger: "<<e.what()<<endl;
536 }
537 catch(PDNSException& e) {
538 g_log<<Logger::Error<<"Error while starting outgoing protobuf logger: "<<e.reason<<endl;
539 }
540 }
541 else {
542 g_log<<Logger::Error<<"Only one outgoingProtobufServer() directive can be configured, we already have "<<lci.outgoingProtobufExportConfig.servers.at(0).toString()<<endl;
543 }
544 });
545 #endif
546
547 #ifdef HAVE_FSTRM
548 Lua.writeFunction("dnstapFrameStreamServer", [&lci](boost::variant<const std::string, const std::unordered_map<int, std::string>> servers, boost::optional<frameStreamOptions_t> vars) {
549 if (!lci.frameStreamExportConfig.enabled) {
550
551 lci.frameStreamExportConfig.enabled = true;
552
553 try {
554 if (servers.type() == typeid(std::string)) {
555 auto server = boost::get<const std::string>(servers);
556 if (!boost::starts_with(server, "/")) {
557 ComboAddress parsecheck(server);
558 }
559 lci.frameStreamExportConfig.servers.emplace_back(server);
560 }
561 else {
562 auto serversMap = boost::get<const std::unordered_map<int,std::string>>(servers);
563 for (const auto& serverPair : serversMap) {
564 lci.frameStreamExportConfig.servers.emplace_back(serverPair.second);
565 }
566 }
567
568 parseFrameStreamOptions(vars, lci.frameStreamExportConfig);
569 }
570 catch(std::exception& e) {
571 g_log<<Logger::Error<<"Error reading config for dnstap framestream logger: "<<e.what()<<endl;
572 }
573 catch(PDNSException& e) {
574 g_log<<Logger::Error<<"Error reading config for dnstap framestream logger: "<<e.reason<<endl;
575 }
576 }
577 else {
578 g_log<<Logger::Error<<"Only one dnstapFrameStreamServer() directive can be configured, we already have "<<lci.frameStreamExportConfig.servers.at(0)<<endl;
579 }
580 });
581 #endif /* HAVE_FSTRM */
582
583 try {
584 Lua.executeCode(ifs);
585 g_luaconfs.setState(std::move(lci));
586 }
587 catch(const LuaContext::ExecutionErrorException& e) {
588 g_log<<Logger::Error<<"Unable to load Lua script from '"+fname+"': ";
589 try {
590 std::rethrow_if_nested(e);
591 } catch(const std::exception& exp) {
592 // exp is the exception that was thrown from inside the lambda
593 g_log << exp.what() << std::endl;
594 }
595 catch(const PDNSException& exp) {
596 // exp is the exception that was thrown from inside the lambda
597 g_log << exp.reason << std::endl;
598 }
599 throw;
600
601 }
602 catch(std::exception& err) {
603 g_log<<Logger::Error<<"Unable to load Lua script from '"+fname+"': "<<err.what()<<endl;
604 throw;
605 }
606
607 }
608
609 void startLuaConfigDelayedThreads(const luaConfigDelayedThreads& delayedThreads, uint64_t generation)
610 {
611 for (const auto& rpzMaster : delayedThreads.rpzMasterThreads) {
612 try {
613 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);
614 t.detach();
615 }
616 catch(const std::exception& e) {
617 g_log<<Logger::Error<<"Problem starting RPZIXFRTracker thread: "<<e.what()<<endl;
618 exit(1); // FIXME proper exit code?
619 }
620 catch(const PDNSException& e) {
621 g_log<<Logger::Error<<"Problem starting RPZIXFRTracker thread: "<<e.reason<<endl;
622 exit(1); // FIXME proper exit code?
623 }
624 }
625 }