You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

633 lines
24 KiB

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