2 #include "ext/luawrapper/include/LuaContext.hpp"
6 #include "namespaces.hh"
8 #include "lua-base4.hh"
9 #include "rec-lua-conf.hh"
10 #include "sortlist.hh"
11 #include "filterpo.hh"
13 #include "rpzloader.hh"
15 #include "remote_logger.hh"
16 #include "validate.hh"
17 #include "validate-recursor.hh"
18 #include "root-dnssec.hh"
20 GlobalStateHolder
<LuaConfigItems
> g_luaconfs
;
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.
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.
29 If someone loads an empty Lua file, the default LuaConfigItems struct MUST MAKE SENSE.
31 To make this easy on you, here is a LuaConfigItems constructor where you
32 can set sane defaults:
35 LuaConfigItems::LuaConfigItems()
37 DNSName
root("."); // don't use g_rootdnsname here, it might not exist yet
38 for (const auto& dsRecord
: rootDSs
) {
39 auto ds
= std::dynamic_pointer_cast
<DSRecordContent
>(DSRecordContent::make(dsRecord
));
40 dsAnchors
[root
].insert(*ds
);
44 /* DID YOU READ THE STORY ABOVE? */
46 bool operator==(const ProtobufExportConfig
& configA
, const ProtobufExportConfig
& configB
)
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
;
63 bool operator!=(const ProtobufExportConfig
& configA
, const ProtobufExportConfig
& configB
)
65 return !(configA
== configB
);
68 bool operator==(const FrameStreamExportConfig
& configA
, const FrameStreamExportConfig
& configB
)
71 return configA
.enabled
== configB
.enabled
&&
72 configA
.logQueries
== configB
.logQueries
&&
73 configA
.logResponses
== configB
.logResponses
&&
74 configA
.logNODs
== configB
.logNODs
&&
75 configA
.logUDRs
== configB
.logUDRs
&&
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
;
86 bool operator!=(const FrameStreamExportConfig
& configA
, const FrameStreamExportConfig
& configB
)
88 return !(configA
== configB
);
92 typename
C::value_type::second_type
constGet(const C
& c
, const std::string
& name
)
94 auto iter
= c
.find(name
);
100 typedef std::unordered_map
<std::string
, boost::variant
<bool, uint32_t, std::string
, std::vector
<std::pair
<int, std::string
>>>> rpzOptions_t
;
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
)
104 if (have
.count("policyName") != 0) {
105 polName
= boost::get
<std::string
>(have
["policyName"]);
107 if (have
.count("defpol") != 0) {
108 defpol
= DNSFilterEngine::Policy();
109 defpol
->d_kind
= (DNSFilterEngine::PolicyKind
)boost::get
<uint32_t>(have
["defpol"]);
110 defpol
->setName(polName
);
111 if (defpol
->d_kind
== DNSFilterEngine::PolicyKind::Custom
) {
112 defpol
->d_custom
.push_back(DNSRecordContent::mastermake(QType::CNAME
, QClass::IN
,
113 boost::get
<string
>(have
["defcontent"])));
115 if (have
.count("defttl") != 0) {
116 defpol
->d_ttl
= static_cast<int32_t>(boost::get
<uint32_t>(have
["defttl"]));
119 defpol
->d_ttl
= -1; // get it from the zone
123 if (have
.count("defpolOverrideLocalData") != 0) {
124 defpolOverrideLocal
= boost::get
<bool>(have
["defpolOverrideLocalData"]);
127 if (have
.count("maxTTL") != 0) {
128 maxTTL
= boost::get
<uint32_t>(have
["maxTTL"]);
130 if (have
.count("zoneSizeHint") != 0) {
131 auto zoneSizeHint
= static_cast<size_t>(boost::get
<uint32_t>(have
["zoneSizeHint"]));
132 if (zoneSizeHint
> 0) {
133 zone
->reserve(zoneSizeHint
);
136 if (have
.count("tags") != 0) {
137 const auto tagsTable
= boost::get
<std::vector
<std::pair
<int, std::string
>>>(have
["tags"]);
138 std::unordered_set
<std::string
> tags
;
139 for (const auto& tag
: tagsTable
) {
140 tags
.insert(tag
.second
);
142 zone
->setTags(std::move(tags
));
144 if (have
.count("overridesGettag") != 0) {
145 zone
->setPolicyOverridesGettag(boost::get
<bool>(have
["overridesGettag"]));
147 if (have
.count("extendedErrorCode") != 0) {
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");
153 zone
->setExtendedErrorCode(static_cast<uint16_t>(code
));
154 if (have
.count("extendedErrorExtra") != 0) {
155 zone
->setExtendedErrorExtra(boost::get
<std::string
>(have
["extendedErrorExtra"]));
158 if (have
.count("includeSOA") != 0) {
159 zone
->setIncludeSOA(boost::get
<bool>(have
["includeSOA"]));
163 typedef std::unordered_map
<std::string
, boost::variant
<bool, uint64_t, std::string
, std::vector
<std::pair
<int, std::string
>>>> protobufOptions_t
;
165 static void parseProtobufOptions(boost::optional
<protobufOptions_t
> vars
, ProtobufExportConfig
& config
)
171 if (vars
->count("timeout")) {
172 config
.timeout
= boost::get
<uint64_t>((*vars
)["timeout"]);
175 if (vars
->count("maxQueuedEntries")) {
176 config
.maxQueuedEntries
= boost::get
<uint64_t>((*vars
)["maxQueuedEntries"]);
179 if (vars
->count("reconnectWaitTime")) {
180 config
.reconnectWaitTime
= boost::get
<uint64_t>((*vars
)["reconnectWaitTime"]);
183 if (vars
->count("asyncConnect")) {
184 config
.asyncConnect
= boost::get
<bool>((*vars
)["asyncConnect"]);
187 if (vars
->count("taggedOnly")) {
188 config
.taggedOnly
= boost::get
<bool>((*vars
)["taggedOnly"]);
191 if (vars
->count("logQueries")) {
192 config
.logQueries
= boost::get
<bool>((*vars
)["logQueries"]);
195 if (vars
->count("logResponses")) {
196 config
.logResponses
= boost::get
<bool>((*vars
)["logResponses"]);
199 if (vars
->count("logMappedFrom")) {
200 config
.logMappedFrom
= boost::get
<bool>((*vars
)["logMappedFrom"]);
203 if (vars
->count("exportTypes")) {
204 config
.exportTypes
.clear();
206 auto types
= boost::get
<std::vector
<std::pair
<int, std::string
>>>((*vars
)["exportTypes"]);
207 for (const auto& pair
: types
) {
208 const auto& type
= pair
.second
;
212 qtype
= std::stoul(type
);
214 catch (const std::exception
& ex
) {
215 qtype
= QType::chartocode(type
.c_str());
217 throw std::runtime_error("Unknown QType '" + type
+ "' in protobuf's export types");
220 config
.exportTypes
.insert(qtype
);
226 typedef std::unordered_map
<std::string
, boost::variant
<bool, uint64_t, std::string
, std::vector
<std::pair
<int, std::string
>>>> frameStreamOptions_t
;
228 static void parseFrameStreamOptions(boost::optional
<frameStreamOptions_t
> vars
, FrameStreamExportConfig
& config
)
234 if (vars
->count("logQueries")) {
235 config
.logQueries
= boost::get
<bool>((*vars
)["logQueries"]);
237 if (vars
->count("logResponses")) {
238 config
.logResponses
= boost::get
<bool>((*vars
)["logResponses"]);
240 if (vars
->count("logNODs")) {
241 config
.logNODs
= boost::get
<bool>((*vars
)["logNODs"]);
243 if (vars
->count("logUDRs")) {
244 config
.logUDRs
= boost::get
<bool>((*vars
)["logUDRs"]);
247 if (vars
->count("bufferHint")) {
248 config
.bufferHint
= boost::get
<uint64_t>((*vars
)["bufferHint"]);
250 if (vars
->count("flushTimeout")) {
251 config
.flushTimeout
= boost::get
<uint64_t>((*vars
)["flushTimeout"]);
253 if (vars
->count("inputQueueSize")) {
254 config
.inputQueueSize
= boost::get
<uint64_t>((*vars
)["inputQueueSize"]);
256 if (vars
->count("outputQueueSize")) {
257 config
.outputQueueSize
= boost::get
<uint64_t>((*vars
)["outputQueueSize"]);
259 if (vars
->count("queueNotifyThreshold")) {
260 config
.queueNotifyThreshold
= boost::get
<uint64_t>((*vars
)["queueNotifyThreshold"]);
262 if (vars
->count("reopenInterval")) {
263 config
.reopenInterval
= boost::get
<uint64_t>((*vars
)["reopenInterval"]);
266 #endif /* HAVE_FSTRM */
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
)
270 boost::optional
<DNSFilterEngine::Policy
> defpol
;
271 bool defpolOverrideLocal
= true;
272 std::shared_ptr
<DNSFilterEngine::Zone
> zone
= std::make_shared
<DNSFilterEngine::Zone
>();
274 uint32_t refresh
= 0;
275 size_t maxReceivedXFRMBytes
= 0;
276 uint16_t axfrTimeout
= 20;
277 uint32_t maxTTL
= std::numeric_limits
<uint32_t>::max();
278 ComboAddress localAddress
;
279 std::vector
<ComboAddress
> primaries
;
280 if (primaries_
.type() == typeid(string
)) {
281 primaries
.push_back(ComboAddress(boost::get
<std::string
>(primaries_
), 53));
284 for (const auto& primary
: boost::get
<std::vector
<std::pair
<int, std::string
>>>(primaries_
)) {
285 primaries
.push_back(ComboAddress(primary
.second
, 53));
290 std::string dumpFile
;
291 std::shared_ptr
<const SOARecordContent
> sr
= nullptr;
294 std::string seedFile
;
295 std::string
polName(zoneName
);
298 auto& have
= *options
;
299 parseRPZParameters(have
, zone
, polName
, defpol
, defpolOverrideLocal
, maxTTL
);
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
))
305 throw std::runtime_error("TSIG secret is not valid Base-64 encoded");
308 if (have
.count("refresh")) {
309 refresh
= boost::get
<uint32_t>(have
["refresh"]);
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"));
316 if (have
.count("maxReceivedMBytes")) {
317 maxReceivedXFRMBytes
= static_cast<size_t>(boost::get
<uint32_t>(have
["maxReceivedMBytes"]));
320 if (have
.count("localAddress")) {
321 localAddress
= ComboAddress(boost::get
<string
>(have
["localAddress"]));
324 if (have
.count("axfrTimeout")) {
325 axfrTimeout
= static_cast<uint16_t>(boost::get
<uint32_t>(have
["axfrTimeout"]));
328 if (have
.count("seedFile")) {
329 seedFile
= boost::get
<std::string
>(have
["seedFile"]);
332 if (have
.count("dumpFile")) {
333 dumpFile
= boost::get
<std::string
>(have
["dumpFile"]);
337 if (localAddress
!= ComboAddress()) {
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
) {
341 throw PDNSException("Primary address(" + primary
.toString() + ") is not of the same Address Family as the local address (" + localAddress
.toString() + ").");
346 DNSName
domain(zoneName
);
347 zone
->setDomain(domain
);
348 zone
->setName(polName
);
349 zoneIdx
= lci
.dfe
.addZone(zone
);
351 auto log
= lci
.d_slog
->withValues("seedfile", Logging::Loggable(seedFile
), "zone", Logging::Loggable(zoneName
));
352 if (!seedFile
.empty()) {
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"));
356 sr
= loadRPZFromFile(seedFile
, zone
, defpol
, defpolOverrideLocal
, maxTTL
);
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() + ")");
363 throw PDNSException("The RPZ zone " + zoneName
+ " loaded from the seed file (" + zone
->getDomain().toString() + ") has no SOA record");
366 catch (const PDNSException
& e
) {
367 SLOG(g_log
<< Logger::Warning
<< "Unable to pre-load RPZ zone " << zoneName
<< " from seed file '" << seedFile
<< "': " << e
.reason
<< endl
,
368 log
->error(Logr::Warning
, e
.reason
, "Exception while pre-loading RPZ zone", "exception", Logging::Loggable("PDNSException")));
371 catch (const std::exception
& e
) {
372 SLOG(g_log
<< Logger::Warning
<< "Unable to pre-load RPZ zone " << zoneName
<< " from seed file '" << seedFile
<< "': " << e
.what() << endl
,
373 log
->error(Logr::Warning
, e
.what(), "Exception while pre-loading RPZ zone", "exception", Logging::Loggable("std::exception")));
378 catch (const std::exception
& e
) {
379 SLOG(g_log
<< Logger::Error
<< "Problem configuring 'rpzPrimary': " << e
.what() << endl
,
380 lci
.d_slog
->error(Logr::Error
, e
.what(), "Exception configuring 'rpzPrimary'", "exception", Logging::Loggable("std::exception")));
382 catch (const PDNSException
& e
) {
383 SLOG(g_log
<< Logger::Error
<< "Problem configuring 'rpzPrimary': " << e
.reason
<< endl
,
384 lci
.d_slog
->error(Logr::Error
, e
.reason
, "Exception configuring 'rpzPrimary'", Logging::Loggable("PDNSException")));
387 delayedThreads
.rpzPrimaryThreads
.emplace_back(primaries
, defpol
, defpolOverrideLocal
, maxTTL
, zoneIdx
, tt
, maxReceivedXFRMBytes
, localAddress
, axfrTimeout
, refresh
, sr
, dumpFile
);
390 // A wrapper class that loads the standard Lua defintions into the context, so that we can use things like pdns.A
391 class RecLuaConfigContext
: public BaseLua4
394 RecLuaConfigContext()
398 void postPrepareContext() override
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
)}
409 void postLoad() override
412 LuaContext
* operator->()
418 void loadRecursorLuaConfig(const std::string
& fname
, luaConfigDelayedThreads
& delayedThreads
, ProxyMapping
& proxyMapping
)
421 lci
.d_slog
= g_slog
->withName("luaconfig");
423 RecLuaConfigContext Lua
;
429 throw PDNSException("Cannot open file '" + fname
+ "': " + stringerror());
431 auto luaconfsLocal
= g_luaconfs
.getLocal();
432 lci
.generation
= luaconfsLocal
->generation
+ 1;
434 Lua
->writeFunction("clearSortlist", [&lci
]() { lci
.sortlist
.clear(); });
436 /* we can get: "1.2.3.4"
437 {"1.2.3.4", "4.5.6.7"}
438 {"1.2.3.4", {"4.5.6.7", "8.9.10.11"}}
441 map
<string
, DNSFilterEngine::PolicyKind
> pmap
{
442 {"NoAction", DNSFilterEngine::PolicyKind::NoAction
},
443 {"Drop", DNSFilterEngine::PolicyKind::Drop
},
444 {"NXDOMAIN", DNSFilterEngine::PolicyKind::NXDOMAIN
},
445 {"NODATA", DNSFilterEngine::PolicyKind::NODATA
},
446 {"Truncate", DNSFilterEngine::PolicyKind::Truncate
},
447 {"Custom", DNSFilterEngine::PolicyKind::Custom
}};
448 Lua
->writeVariable("Policy", pmap
);
450 Lua
->writeFunction("rpzFile", [&lci
](const string
& filename
, boost::optional
<rpzOptions_t
> options
) {
451 auto log
= lci
.d_slog
->withValues("file", Logging::Loggable(filename
));
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();
459 auto& have
= *options
;
460 parseRPZParameters(have
, zone
, polName
, defpol
, defpolOverrideLocal
, maxTTL
);
462 SLOG(g_log
<< Logger::Warning
<< "Loading RPZ from file '" << filename
<< "'" << endl
,
463 log
->info(Logr::Info
, "Loading RPZ from file"));
464 zone
->setName(polName
);
465 loadRPZFromFile(filename
, zone
, defpol
, defpolOverrideLocal
, maxTTL
);
466 lci
.dfe
.addZone(zone
);
467 SLOG(g_log
<< Logger::Warning
<< "Done loading RPZ from file '" << filename
<< "'" << endl
,
468 log
->info(Logr::Info
, "Done loading RPZ from file"));
470 catch (const std::exception
& e
) {
471 SLOG(g_log
<< Logger::Error
<< "Unable to load RPZ zone from '" << filename
<< "': " << e
.what() << endl
,
472 log
->error(Logr::Error
, e
.what(), "Exception while loading RPZ zone from file"));
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
) {
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"));
479 rpzPrimary(lci
, delayedThreads
, primaries_
, zoneName
, options
);
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
) {
482 rpzPrimary(lci
, delayedThreads
, primaries_
, zoneName
, options
);
485 typedef std::unordered_map
<std::string
, boost::variant
<uint32_t, std::string
>> zoneToCacheOptions_t
;
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
) {
489 RecZoneToCache::Config conf
;
490 DNSName
validZoneName(zoneName
);
491 conf
.d_zone
= zoneName
;
492 const set
<string
> methods
= {"axfr", "url", "file"};
493 if (methods
.count(method
) == 0) {
494 throw std::runtime_error("unknwon method '" + method
+ "'");
496 conf
.d_method
= method
;
497 if (srcs
.type() == typeid(std::string
)) {
498 conf
.d_sources
.push_back(boost::get
<std::string
>(srcs
));
501 for (const auto& src
: boost::get
<std::vector
<std::pair
<int, std::string
>>>(srcs
)) {
502 conf
.d_sources
.push_back(src
.second
);
505 if (conf
.d_sources
.size() == 0) {
506 throw std::runtime_error("at least one source required");
509 auto& have
= *options
;
510 if (have
.count("timeout")) {
511 conf
.d_timeout
= boost::get
<uint32_t>(have
.at("timeout"));
513 if (have
.count("tsigname")) {
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
)) {
517 throw std::runtime_error("TSIG secret is not valid Base-64 encoded");
520 if (have
.count("maxReceivedMBytes")) {
521 conf
.d_maxReceivedBytes
= static_cast<size_t>(boost::get
<uint32_t>(have
.at("maxReceivedMBytes")));
522 conf
.d_maxReceivedBytes
*= 1024 * 1024;
524 if (have
.count("localAddress")) {
525 conf
.d_local
= ComboAddress(boost::get
<string
>(have
.at("localAddress")));
527 if (have
.count("refreshPeriod")) {
528 conf
.d_refreshPeriod
= boost::get
<uint32_t>(have
.at("refreshPeriod"));
530 if (have
.count("retryOnErrorPeriod")) {
531 conf
.d_retryOnError
= boost::get
<uint32_t>(have
.at("retryOnErrorPeriod"));
533 const map
<string
, pdns::ZoneMD::Config
> nameToVal
= {
534 {"ignore", pdns::ZoneMD::Config::Ignore
},
535 {"validate", pdns::ZoneMD::Config::Validate
},
536 {"require", pdns::ZoneMD::Config::Require
},
538 if (have
.count("zonemd")) {
539 string zonemdValidation
= boost::get
<string
>(have
.at("zonemd"));
540 auto it
= nameToVal
.find(zonemdValidation
);
541 if (it
== nameToVal
.end()) {
542 throw std::runtime_error(zonemdValidation
+ " is not a valid value for `zonemd`");
545 conf
.d_zonemd
= it
->second
;
548 if (have
.count("dnssec")) {
549 string dnssec
= boost::get
<string
>(have
.at("dnssec"));
550 auto it
= nameToVal
.find(dnssec
);
551 if (it
== nameToVal
.end()) {
552 throw std::runtime_error(dnssec
+ " is not a valid value for `dnssec`");
555 conf
.d_dnssec
= it
->second
;
560 lci
.ztcConfigs
[validZoneName
] = conf
;
562 catch (const std::exception
& e
) {
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")));
569 typedef vector
<pair
<int, boost::variant
<string
, vector
<pair
<int, string
>>>>> argvec_t
;
570 Lua
->writeFunction("addSortList",
571 [&lci
](const std::string
& formask_
,
572 const boost::variant
<string
, argvec_t
>& masks
,
573 boost::optional
<int> order_
) {
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
);
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
);
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
);
595 catch (std::exception
& e
) {
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")));
601 Lua
->writeFunction("addTA", [&lci
](const std::string
& who
, const std::string
& what
) {
602 warnIfDNSSECDisabled("Warning: adding Trust Anchor for DNSSEC (addTA), but dnssec is set to 'off'!");
604 auto ds
= std::dynamic_pointer_cast
<DSRecordContent
>(DSRecordContent::make(what
));
605 lci
.dsAnchors
[zone
].insert(*ds
);
608 Lua
->writeFunction("clearTA", [&lci
](boost::optional
<string
> who
) {
609 warnIfDNSSECDisabled("Warning: removing Trust Anchor for DNSSEC (clearTA), but dnssec is set to 'off'!");
611 lci
.dsAnchors
.erase(DNSName(*who
));
613 lci
.dsAnchors
.clear();
617 Lua
->writeFunction("addDS", [&lci
](const std::string
& who
, const std::string
& what
) {
618 warnIfDNSSECDisabled("Warning: adding Trust Anchor for DNSSEC (addDS), but dnssec is set to 'off'!");
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"));
622 auto ds
= std::dynamic_pointer_cast
<DSRecordContent
>(DSRecordContent::make(what
));
623 lci
.dsAnchors
[zone
].insert(*ds
);
627 Lua
->writeFunction("clearDS", [&lci
](boost::optional
<string
> who
) {
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"));
630 warnIfDNSSECDisabled("Warning: removing Trust Anchor for DNSSEC (clearDS), but dnssec is set to 'off'!");
632 lci
.dsAnchors
.erase(DNSName(*who
));
634 lci
.dsAnchors
.clear();
637 Lua
->writeFunction("addNTA", [&lci
](const std::string
& who
, const boost::optional
<std::string
> why
) {
638 warnIfDNSSECDisabled("Warning: adding Negative Trust Anchor for DNSSEC (addNTA), but dnssec is set to 'off'!");
640 lci
.negAnchors
[DNSName(who
)] = static_cast<string
>(*why
);
642 lci
.negAnchors
[DNSName(who
)] = "";
645 Lua
->writeFunction("clearNTA", [&lci
](boost::optional
<string
> who
) {
646 warnIfDNSSECDisabled("Warning: removing Negative Trust Anchor for DNSSEC (clearNTA), but dnssec is set to 'off'!");
648 lci
.negAnchors
.erase(DNSName(*who
));
650 lci
.negAnchors
.clear();
653 Lua
->writeFunction("readTrustAnchorsFromFile", [&lci
](const std::string
& fnamearg
, const boost::optional
<uint32_t> interval
) {
654 uint32_t realInterval
= 24;
656 realInterval
= static_cast<uint32_t>(*interval
);
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
;
661 updateTrustAnchorsFromFile(fnamearg
, lci
.dsAnchors
, lci
.d_slog
);
664 Lua
->writeFunction("setProtobufMasks", [&lci
](const uint8_t maskV4
, uint8_t maskV6
) {
665 lci
.protobufMaskV4
= maskV4
;
666 lci
.protobufMaskV6
= maskV6
;
669 Lua
->writeFunction("protobufServer", [&lci
](boost::variant
<const std::string
, const std::unordered_map
<int, std::string
>> servers
, boost::optional
<protobufOptions_t
> vars
) {
670 if (!lci
.protobufExportConfig
.enabled
) {
672 lci
.protobufExportConfig
.enabled
= true;
675 if (servers
.type() == typeid(std::string
)) {
676 auto server
= boost::get
<const std::string
>(servers
);
678 lci
.protobufExportConfig
.servers
.emplace_back(server
);
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
);
687 parseProtobufOptions(vars
, lci
.protobufExportConfig
);
689 catch (std::exception
& e
) {
690 SLOG(g_log
<< Logger::Error
<< "Error while adding protobuf logger: " << e
.what() << endl
,
691 lci
.d_slog
->error(Logr::Error
, e
.what(), "Exception while adding protobuf logger", "exception", Logging::Loggable("std::exception")));
693 catch (PDNSException
& e
) {
694 SLOG(g_log
<< Logger::Error
<< "Error while adding protobuf logger: " << e
.reason
<< endl
,
695 lci
.d_slog
->error(Logr::Error
, e
.reason
, "Exception while adding protobuf logger", "exception", Logging::Loggable("PDNSException")));
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())));
704 Lua
->writeFunction("outgoingProtobufServer", [&lci
](boost::variant
<const std::string
, const std::unordered_map
<int, std::string
>> servers
, boost::optional
<protobufOptions_t
> vars
) {
705 if (!lci
.outgoingProtobufExportConfig
.enabled
) {
707 lci
.outgoingProtobufExportConfig
.enabled
= true;
710 if (servers
.type() == typeid(std::string
)) {
711 auto server
= boost::get
<const std::string
>(servers
);
713 lci
.outgoingProtobufExportConfig
.servers
.emplace_back(server
);
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
);
722 parseProtobufOptions(vars
, lci
.outgoingProtobufExportConfig
);
724 catch (std::exception
& e
) {
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")));
728 catch (PDNSException
& e
) {
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")));
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())));
740 Lua
->writeFunction("dnstapFrameStreamServer", [&lci
](boost::variant
<const std::string
, const std::unordered_map
<int, std::string
>> servers
, boost::optional
<frameStreamOptions_t
> vars
) {
741 if (!lci
.frameStreamExportConfig
.enabled
) {
743 lci
.frameStreamExportConfig
.enabled
= true;
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
);
751 lci
.frameStreamExportConfig
.servers
.emplace_back(server
);
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
);
760 parseFrameStreamOptions(vars
, lci
.frameStreamExportConfig
);
762 catch (std::exception
& e
) {
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")));
766 catch (PDNSException
& e
) {
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")));
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))));
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;
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
);
786 lci
.nodFrameStreamExportConfig
.servers
.emplace_back(server
);
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
);
795 parseFrameStreamOptions(vars
, lci
.nodFrameStreamExportConfig
);
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")));
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")));
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))));
811 #endif /* HAVE_FSTRM */
813 Lua
->writeFunction("addAllowedAdditionalQType", [&lci
](int qtype
, std::unordered_map
<int, int> targetqtypes
, boost::optional
<std::map
<std::string
, int>> options
) {
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())));
827 std::set
<QType
> targets
;
828 for (const auto& t
: targetqtypes
) {
829 targets
.emplace(QType(t
.second
));
832 AdditionalMode mode
= AdditionalMode::CacheOnlyRequireAuth
; // Always cheap and should be safe
835 if (const auto it
= options
->find("mode"); it
!= options
->end()) {
836 mode
= static_cast<AdditionalMode
>(it
->second
);
837 if (mode
> AdditionalMode::ResolveDeferred
) {
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
)));
843 lci
.allowAdditionalQTypes
.insert_or_assign(qtype
, pair(targets
, mode
));
846 Lua
->writeFunction("addProxyMapping", [&proxyMapping
,&lci
](const string
& netmaskArg
, const string
& addressArg
, boost::optional
<std::vector
<pair
<int,std::string
>>> smnStrings
) {
848 Netmask
netmask(netmaskArg
);
849 ComboAddress
address(addressArg
);
850 boost::optional
<SuffixMatchNode
> smn
;
852 smn
= boost::make_optional(SuffixMatchNode
{});
853 for (const auto& el
: *smnStrings
) {
857 proxyMapping
.insert_or_assign(netmask
, {address
, smn
});
859 catch (std::exception
& e
) {
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")));
863 catch (PDNSException
& e
) {
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")));
870 Lua
->executeCode(ifs
);
871 g_luaconfs
.setState(std::move(lci
));
873 catch (const LuaContext::ExecutionErrorException
& e
) {
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
)));
877 std::rethrow_if_nested(e
);
879 catch (const std::exception
& exp
) {
880 // exp is the exception that was thrown from inside the lambda
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")));
884 catch (const PDNSException
& exp
) {
885 // exp is the exception that was thrown from inside the lambda
886 SLOG(g_log
<< exp
.reason
<< std::endl
,
887 lci
.d_slog
->error(Logr::Error
, exp
.reason
, "Exception loading Lua", "exception", Logging::Loggable("PDNSException"))) }
890 catch (std::exception
& err
) {
891 SLOG(g_log
<< Logger::Error
<< "Unable to load Lua script from '" + fname
+ "': " << err
.what() << endl
,
892 lci
.d_slog
->error(Logr::Error
, err
.what(), "Unable to load Lua script", "file", Logging::Loggable(fname
), "exception", Logging::Loggable("std::exception")));
897 void startLuaConfigDelayedThreads(const luaConfigDelayedThreads
& delayedThreads
, uint64_t generation
)
899 for (const auto& rpzPrimary
: delayedThreads
.rpzPrimaryThreads
) {
901 // The get calls all return a value object here. That is essential, since we want copies so that RPZIXFRTracker gets values
902 // with the proper lifetime.
903 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
);
906 catch (const std::exception
& e
) {
907 SLOG(g_log
<< Logger::Error
<< "Problem starting RPZIXFRTracker thread: " << e
.what() << endl
,
908 g_slog
->withName("rpz")->error(Logr::Error
, e
.what(), "Exception starting RPZIXFRTracker thread", "exception", Logging::Loggable("std::exception")));
911 catch (const PDNSException
& e
) {
912 SLOG(g_log
<< Logger::Error
<< "Problem starting RPZIXFRTracker thread: " << e
.reason
<< endl
,
913 g_slog
->withName("rpz")->error(Logr::Error
, e
.reason
, "Exception starting RPZIXFRTracker thread", "exception", Logging::Loggable("PDNSException")));