]>
Commit | Line | Data |
---|---|---|
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 | 20 | GlobalStateHolder<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 | ||
35 | LuaConfigItems::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 |
46 | bool 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 | ||
63 | bool operator!=(const ProtobufExportConfig& configA, const ProtobufExportConfig& configB) | |
64 | { | |
65 | return !(configA == configB); | |
66 | } | |
67 | ||
afaf1b5d FM |
68 | bool 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 | ||
86 | bool operator!=(const FrameStreamExportConfig& configA, const FrameStreamExportConfig& configB) | |
87 | { | |
88 | return !(configA == configB); | |
89 | } | |
90 | ||
ad42489c | 91 | template <typename C> |
92 | typename 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 | 100 | typedef std::unordered_map<std::string, boost::variant<bool, uint32_t, std::string, std::vector<std::pair<int, std::string>>>> rpzOptions_t; |
6a99b9a4 | 101 | |
af231ceb | 102 | static 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 | 163 | typedef std::unordered_map<std::string, boost::variant<bool, uint64_t, std::string, std::vector<std::pair<int, std::string>>>> protobufOptions_t; |
f1c7929a RG |
164 | |
165 | static 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 | 226 | typedef std::unordered_map<std::string, boost::variant<bool, uint64_t, std::string, std::vector<std::pair<int, std::string>>>> frameStreamOptions_t; |
b9fa43e0 OM |
227 | |
228 | static 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 | 268 | static 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 |
391 | class RecLuaConfigContext : public BaseLua4 |
392 | { | |
393 | public: | |
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 | 418 | void 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 |
898 | void 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 | } |