From: Remi Gacogne Date: Tue, 7 Jan 2025 15:28:45 +0000 (+0100) Subject: dnsdist: Support inline and "detached to a file" Lua code in YAML X-Git-Tag: dnsdist-2.0.0-alpha1~160^2~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=be6d0cd29ccfa05ab5fc7eeaff8792bb246bdf92;p=thirdparty%2Fpdns.git dnsdist: Support inline and "detached to a file" Lua code in YAML --- diff --git a/pdns/dnsdistdist/dnsdist-actions-definitions.yml b/pdns/dnsdistdist/dnsdist-actions-definitions.yml index dd0bd648bc..ea8ab18f77 100644 --- a/pdns/dnsdistdist/dnsdist-actions-definitions.yml +++ b/pdns/dnsdistdist/dnsdist-actions-definitions.yml @@ -23,9 +23,14 @@ type: "String" - name: "logger-name" type: "String" - - name: "alter-function" - type: "dnsdist::actions::DnstapAlterFunction" - rust-type: "String" + - name: "alter-function-name" + type: "String" + default: "" + - name: "alter-function-code" + type: "String" + default: "" + - name: "alter-function-file" + type: "String" default: "" - name: "drop" description: "Drop the packet" @@ -114,16 +119,32 @@ Subsequent rules are processed after this action" cpp-optional: false - name: "lua" description: "Invoke a Lua function that accepts a :class:`DNSQuestion`. The function should return a :ref:`DNSAction`. If the Lua code fails, ``ServFail`` is returned" + skip-cpp: true + skip-rust: true parameters: - - name: "function" - type: "dnsdist::actions::LuaActionFunction" - rust-type: "String" + - name: "function-name" + type: "String" + default: "" + - name: "function-code" + type: "String" + default: "" + - name: "function-file" + type: "String" + default: "" - name: "LuaFFI" description: "Invoke a Lua function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``. The function should return a :ref:`DNSAction`. If the Lua code fails, ``ServFail`` is returned" + skip-cpp: true + skip-rust: true parameters: - - name: "function" - type: "dnsdist::actions::LuaActionFFIFunction" - rust-type: "String" + - name: "function-name" + type: "String" + default: "" + - name: "function-code" + type: "String" + default: "" + - name: "function-file" + type: "String" + default: "" - name: "LuaFFIPerThread" description: "Invoke a Lua function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``. The function should return a :ref:`DNSAction`. If the Lua code fails, ``ServFail`` is returned. The function will be invoked in a per-thread Lua state, without access to the global Lua state. All constants (:ref:`DNSQType`, :ref:`DNSRCode`, ...) are available in that per-thread context, as well as all FFI functions. Objects and their bindings that are not usable in a FFI context (:class:`DNSQuestion`, :class:`DNSDistProtoBufMessage`, :class:`PacketCache`, ...) are not available." @@ -198,9 +219,14 @@ The function will be invoked in a per-thread Lua state, without access to the gl parameters: - name: "logger-name" type: "String" - - name: "alter-function" - type: "dnsdist::actions::ProtobufAlterFunction" - rust-type: "String" + - name: "alter-function-name" + type: "String" + default: "" + - name: "alter-function-code" + type: "String" + default: "" + - name: "alter-function-file" + type: "String" default: "" - name: "server-id" type: "String" diff --git a/pdns/dnsdistdist/dnsdist-actions-factory-generated.cc b/pdns/dnsdistdist/dnsdist-actions-factory-generated.cc index 7c1f5a4855..467412d4c8 100644 --- a/pdns/dnsdistdist/dnsdist-actions-factory-generated.cc +++ b/pdns/dnsdistdist/dnsdist-actions-factory-generated.cc @@ -19,14 +19,6 @@ std::shared_ptr getLogAction(const std::string& fileName, bool binary { return std::shared_ptr(new LogAction(fileName, binary, append, buffered, verboseOnly, includeTimestamp)); } -std::shared_ptr getLuaAction(dnsdist::actions::LuaActionFunction function) -{ - return std::shared_ptr(new LuaAction(function)); -} -std::shared_ptr getLuaFFIAction(dnsdist::actions::LuaActionFFIFunction function) -{ - return std::shared_ptr(new LuaFFIAction(function)); -} std::shared_ptr getLuaFFIPerThreadAction(const std::string& code) { return std::shared_ptr(new LuaFFIPerThreadAction(code)); diff --git a/pdns/dnsdistdist/dnsdist-actions-factory-generated.hh b/pdns/dnsdistdist/dnsdist-actions-factory-generated.hh index fb18c7b78d..772040b100 100644 --- a/pdns/dnsdistdist/dnsdist-actions-factory-generated.hh +++ b/pdns/dnsdistdist/dnsdist-actions-factory-generated.hh @@ -4,8 +4,6 @@ std::shared_ptr getDelayAction(uint32_t msec); std::shared_ptr getDropAction(); std::shared_ptr getSetEDNSOptionAction(uint32_t code, const std::string& data); std::shared_ptr getLogAction(const std::string& fileName, bool binary, bool append, bool buffered, bool verboseOnly, bool includeTimestamp); -std::shared_ptr getLuaAction(dnsdist::actions::LuaActionFunction function); -std::shared_ptr getLuaFFIAction(dnsdist::actions::LuaActionFFIFunction function); std::shared_ptr getLuaFFIPerThreadAction(const std::string& code); std::shared_ptr getNoneAction(); std::shared_ptr getPoolAction(const std::string& poolName, bool stopProcessing); diff --git a/pdns/dnsdistdist/dnsdist-actions-factory.cc b/pdns/dnsdistdist/dnsdist-actions-factory.cc index 052d08f7c3..5a0b7c9974 100644 --- a/pdns/dnsdistdist/dnsdist-actions-factory.cc +++ b/pdns/dnsdistdist/dnsdist-actions-factory.cc @@ -2302,6 +2302,26 @@ private: uint32_t d_max{std::numeric_limits::max()}; }; +std::shared_ptr getLuaAction(dnsdist::actions::LuaActionFunction function) +{ + return std::shared_ptr(new LuaAction(function)); +} + +std::shared_ptr getLuaFFIAction(dnsdist::actions::LuaActionFFIFunction function) +{ + return std::shared_ptr(new LuaFFIAction(function)); +} + +std::shared_ptr getLuaResponseAction(dnsdist::actions::LuaResponseActionFunction function) +{ + return std::shared_ptr(new LuaResponseAction(function)); +} + +std::shared_ptr getLuaFFIResponseAction(dnsdist::actions::LuaResponseActionFFIFunction function) +{ + return std::shared_ptr(new LuaFFIResponseAction(function)); +} + #ifndef DISABLE_PROTOBUF std::shared_ptr getRemoteLogAction(RemoteLogActionConfiguration& config) { diff --git a/pdns/dnsdistdist/dnsdist-actions-factory.hh b/pdns/dnsdistdist/dnsdist-actions-factory.hh index 4d2cd45377..8aa98eee13 100644 --- a/pdns/dnsdistdist/dnsdist-actions-factory.hh +++ b/pdns/dnsdistdist/dnsdist-actions-factory.hh @@ -62,6 +62,11 @@ struct SOAParams #include "dnsdist-actions-factory-generated.hh" #include "dnsdist-response-actions-factory-generated.hh" +std::shared_ptr getLuaAction(dnsdist::actions::LuaActionFunction function); +std::shared_ptr getLuaFFIAction(dnsdist::actions::LuaActionFFIFunction function); +std::shared_ptr getLuaResponseAction(dnsdist::actions::LuaResponseActionFunction function); +std::shared_ptr getLuaFFIResponseAction(dnsdist::actions::LuaResponseActionFFIFunction function); + std::shared_ptr getContinueAction(std::shared_ptr action); #ifdef HAVE_DNS_OVER_HTTPS std::shared_ptr getHTTPStatusAction(uint16_t status, PacketBuffer&& body, const std::string& contentType, const dnsdist::ResponseConfig& responseConfig); diff --git a/pdns/dnsdistdist/dnsdist-configuration-yaml.cc b/pdns/dnsdistdist/dnsdist-configuration-yaml.cc index b2185c3f15..a40c21bbe3 100644 --- a/pdns/dnsdistdist/dnsdist-configuration-yaml.cc +++ b/pdns/dnsdistdist/dnsdist-configuration-yaml.cc @@ -115,6 +115,57 @@ static T checkedConversionFromStr(const std::string& context, const std::string& return checkedConversionFromStr(context, parameterName, std::string(str)); } +template +static bool getOptionalLuaFunction(T& destination, const ::rust::string& functionName) +{ + auto lua = g_lua.lock(); + auto function = lua->readVariable>(std::string(functionName)); + if (!function) { + return false; + } + destination = *function; + return true; +} + +static std::optional loadContentFromConfigurationFile(const std::string& fileName) +{ + /* no check on the file size, don't do this with just any file! */ + auto file = std::ifstream(fileName); + if (!file.is_open()) { + return std::nullopt; + } + return std::string(std::istreambuf_iterator(file), {}); +} + +template +static bool getLuaFunctionFromConfiguration(FuncType& destination, const ::rust::string& functionName, const ::rust::string& functionCode, const ::rust::string& functionFile, const std::string& context) +{ + if (!functionName.empty()) { + return getOptionalLuaFunction(destination, functionName); + } + if (!functionCode.empty()) { + auto function = dnsdist::lua::getFunctionFromLuaCode(std::string(functionCode), context); + if (function) { + destination = *function; + return true; + } + throw std::runtime_error("Unable to load a Lua function from the content of lua directive in " + context + " context"); + } + if (!functionFile.empty()) { + auto content = loadContentFromConfigurationFile(std::string(functionFile)); + if (!content) { + throw std::runtime_error("Unable to load content of lua-file's '" + std::string(functionFile) + "' in " + context + " context"); + } + auto function = dnsdist::lua::getFunctionFromLuaCode(*content, context); + if (function) { + destination = *function; + return true; + } + throw std::runtime_error("Unable to load a Lua function from the content of lua-file's '" + std::string(functionFile) + "' in " + context + " context"); + } + return false; +} + static std::set getCPUPiningFromStr(const std::string& context, const std::string& cpuStr) { std::set cpus; @@ -301,18 +352,6 @@ static bool handleTLSConfiguration(const dnsdist::rust::settings::BindConfigurat return true; } -template -static bool getOptionalLuaFunction(T& destination, const ::rust::string& functionName) -{ - auto lua = g_lua.lock(); - auto function = lua->readVariable>(std::string(functionName)); - if (!function) { - return false; - } - destination = *function; - return true; -} - static std::shared_ptr createBackendFromConfiguration(const dnsdist::rust::settings::BackendConfiguration& config, bool configCheck) { DownstreamState::Config backendConfig; @@ -359,7 +398,7 @@ static std::shared_ptr createBackendFromConfiguration(const dns backendConfig.maxCheckFailures = hcConf.max_failures; backendConfig.minRiseSuccesses = hcConf.rise; - getOptionalLuaFunction(backendConfig.checkFunction, hcConf.function); + getLuaFunctionFromConfiguration(backendConfig.checkFunction, hcConf.function, hcConf.lua, hcConf.lua_file, "backend health-check"); auto availability = DownstreamState::getAvailabilityFromStr(std::string(hcConf.mode)); if (availability) { @@ -586,7 +625,7 @@ static void loadDynamicBlockConfiguration(const dnsdist::rust::settings::Dynamic ruleParams.d_tagSettings->d_value = std::string(rule.tag_value); } DynBlockRulesGroup::smtVisitor_t visitor; - getOptionalLuaFunction(visitor, rule.visitor_function); + getLuaFunctionFromConfiguration(visitor, rule.visitor_function_name, rule.visitor_function_code, rule.visitor_function_file, "dynamic block suffix match visitor function"); dbrgObj->setSuffixMatchRule(std::move(ruleParams), std::move(visitor)); } else if (rule.rule_type == "suffix-match-ffi") { @@ -597,7 +636,7 @@ static void loadDynamicBlockConfiguration(const dnsdist::rust::settings::Dynamic ruleParams.d_tagSettings->d_value = std::string(rule.tag_value); } dnsdist_ffi_stat_node_visitor_t visitor; - getOptionalLuaFunction(visitor, rule.visitor_function); + getLuaFunctionFromConfiguration(visitor, rule.visitor_function_name, rule.visitor_function_code, rule.visitor_function_file, "dynamic block suffix match FFI visitor function"); dbrgObj->setSuffixMatchRuleFFI(std::move(ruleParams), std::move(visitor)); } } @@ -747,7 +786,6 @@ static void loadWebServer(const dnsdist::rust::settings::WebserverConfiguration& config.d_apiReadWrite = webConfig.api_read_write; }); } - #endif /* defined(HAVE_YAML_CONFIGURATION) */ bool loadConfigurationFromFile(const std::string& fileName, bool isClient, bool configCheck) @@ -758,8 +796,8 @@ bool loadConfigurationFromFile(const std::string& fileName, bool isClient, bool s_inConfigCheckMode.store(configCheck); s_inClientMode.store(isClient); - auto file = std::ifstream(fileName); - if (!file.is_open()) { + auto data = loadContentFromConfigurationFile(fileName); + if (!data) { errlog("Unable to open YAML file %s: %s", fileName, stringerror(errno)); return false; } @@ -770,9 +808,7 @@ bool loadConfigurationFromFile(const std::string& fileName, bool isClient, bool } try { - auto data = std::string(std::istreambuf_iterator(file), std::istreambuf_iterator()); - - auto globalConfig = dnsdist::rust::settings::from_yaml_string(data); + auto globalConfig = dnsdist::rust::settings::from_yaml_string(*data); if (!globalConfig.console.listen_address.empty()) { const auto& consoleConf = globalConfig.console; @@ -887,9 +923,7 @@ bool loadConfigurationFromFile(const std::string& fileName, bool isClient, bool if (globalConfig.query_count.enabled) { dnsdist::configuration::updateRuntimeConfiguration([&globalConfig](dnsdist::configuration::RuntimeConfiguration& config) { config.d_queryCountConfig.d_enabled = true; - if (!globalConfig.query_count.filter.empty()) { - getOptionalLuaFunction(config.d_queryCountConfig.d_filter, globalConfig.query_count.filter); - } + getLuaFunctionFromConfiguration(config.d_queryCountConfig.d_filter, globalConfig.query_count.filter_function_name, globalConfig.query_count.filter_function_code, globalConfig.query_count.filter_function_file, "query count filter function"); }); } @@ -939,14 +973,14 @@ bool loadConfigurationFromFile(const std::string& fileName, bool isClient, bool for (const auto& policy : globalConfig.load_balancing_policies.custom_policies) { if (policy.ffi) { if (policy.per_thread) { - auto policyObj = std::make_shared(std::string(policy.name), std::string(policy.function)); + auto policyObj = std::make_shared(std::string(policy.name), std::string(policy.function_code)); registerType(policyObj, policy.name); } else { ServerPolicy::ffipolicyfunc_t function; - if (!getOptionalLuaFunction(function, policy.function)) { - throw std::runtime_error("Custom FFI load-balancing policy '" + std::string(policy.name) + "' is referring to a non-existent Lua function '" + std::string(policy.function) + "'"); + if (!getLuaFunctionFromConfiguration(function, policy.function_name, policy.function_code, policy.function_file, "FFI load-balancing policy")) { + throw std::runtime_error("Custom FFI load-balancing policy '" + std::string(policy.name) + "' could not be created: no valid function name, Lua code or Lua file"); } auto policyObj = std::make_shared(std::string(policy.name), std::move(function)); registerType(policyObj, policy.name); @@ -954,8 +988,8 @@ bool loadConfigurationFromFile(const std::string& fileName, bool isClient, bool } else { ServerPolicy::policyfunc_t function; - if (!getOptionalLuaFunction(function, policy.function)) { - throw std::runtime_error("Custom load-balancing policy '" + std::string(policy.name) + "' is referring to a non-existent Lua function '" + std::string(policy.function) + "'"); + if (!getLuaFunctionFromConfiguration(function, policy.function_name, policy.function_code, policy.function_file, "load-balancing policy")) { + throw std::runtime_error("Custom load-balancing policy '" + std::string(policy.name) + "' could not be created: no valid function name, Lua code or Lua file"); } auto policyObj = std::make_shared(std::string(policy.name), std::move(function), true); registerType(policyObj, policy.name); @@ -1091,14 +1125,24 @@ static std::vector<::SVCRecordParameters> convertSVCRecordParameters(const ::rus return cppParameters; } -template -T convertLuaFunction(const ::rust::String& context, const ::rust::String& name) +std::shared_ptr getLuaAction(const LuaActionConfiguration& config) { - T function; - if (!dnsdist::configuration::yaml::getOptionalLuaFunction(function, name)) { - throw std::runtime_error("Context '" + std::string(context) + "' is referring to a non-existent Lua function '" + std::string(name) + "'"); + dnsdist::actions::LuaActionFunction function; + if (!dnsdist::configuration::yaml::getLuaFunctionFromConfiguration(function, config.function_name, config.function_code, config.function_file, "Lua action")) { + throw std::runtime_error("Lua action '" + std::string(config.name) + "' could not be created: no valid function name, Lua code or Lua file"); } - return function; + auto action = dnsdist::actions::getLuaAction(std::move(function)); + return newDNSActionWrapper(std::move(action), config.name); +} + +std::shared_ptr getLuaFFIAction(const LuaFFIActionConfiguration& config) +{ + dnsdist::actions::LuaActionFFIFunction function; + if (!dnsdist::configuration::yaml::getLuaFunctionFromConfiguration(function, config.function_name, config.function_code, config.function_file, "Lua action")) { + throw std::runtime_error("Lua FFI action '" + std::string(config.name) + "' could not be created: no valid function name, Lua code or Lua file"); + } + auto action = dnsdist::actions::getLuaFFIAction(std::move(function)); + return newDNSActionWrapper(std::move(action), config.name); } std::shared_ptr getContinueAction(const ContinueActionConfiguration& config) @@ -1159,6 +1203,26 @@ std::shared_ptr getSpoofRawAction(const SpoofRawActionConfigur return newDNSActionWrapper(std::move(action), config.name); } +std::shared_ptr getLuaResponseAction(const LuaResponseActionConfiguration& config) +{ + dnsdist::actions::LuaResponseActionFunction function; + if (!dnsdist::configuration::yaml::getLuaFunctionFromConfiguration(function, config.function_name, config.function_code, config.function_file, "Lua action")) { + throw std::runtime_error("Lua response action '" + std::string(config.name) + "' could not be created: no valid function name, Lua code or Lua file"); + } + auto action = dnsdist::actions::getLuaResponseAction(std::move(function)); + return newDNSResponseActionWrapper(std::move(action), config.name); +} + +std::shared_ptr getLuaFFIResponseAction(const LuaFFIResponseActionConfiguration& config) +{ + dnsdist::actions::LuaResponseActionFFIFunction function; + if (!dnsdist::configuration::yaml::getLuaFunctionFromConfiguration(function, config.function_name, config.function_code, config.function_file, "Lua action")) { + throw std::runtime_error("Lua FFI response action '" + std::string(config.name) + "' could not be created: no valid function name, Lua code or Lua file"); + } + auto action = dnsdist::actions::getLuaFFIResponseAction(std::move(function)); + return newDNSResponseActionWrapper(std::move(action), config.name); +} + std::shared_ptr getClearRecordTypesResponseAction(const ClearRecordTypesResponseActionConfiguration& config) { std::unordered_set qtypes{}; @@ -1297,7 +1361,7 @@ std::shared_ptr getDnstapLogAction(const DnstapLogActionConfig throw std::runtime_error("Unable to find the dnstap logger named '" + std::string(config.logger_name) + "'"); } dnsdist::actions::DnstapAlterFunction alterFunc; - dnsdist::configuration::yaml::getOptionalLuaFunction(alterFunc, config.alter_function); + dnsdist::configuration::yaml::getLuaFunctionFromConfiguration(alterFunc, config.alter_function_name, config.alter_function_code, config.alter_function_file, "dnstap log action"); auto action = dnsdist::actions::getDnstapLogAction(std::string(config.identity), logger, alterFunc); return newDNSActionWrapper(std::move(action), config.name); #endif @@ -1313,7 +1377,7 @@ std::shared_ptr getDnstapLogResponseAction(const Dnsta throw std::runtime_error("Unable to find the dnstap logger named '" + std::string(config.logger_name) + "'"); } dnsdist::actions::DnstapAlterResponseFunction alterFunc; - dnsdist::configuration::yaml::getOptionalLuaFunction(alterFunc, config.alter_function); + dnsdist::configuration::yaml::getLuaFunctionFromConfiguration(alterFunc, config.alter_function_name, config.alter_function_code, config.alter_function_file, "dnstap log response action"); auto action = dnsdist::actions::getDnstapLogResponseAction(std::string(config.identity), logger, alterFunc); return newDNSResponseActionWrapper(std::move(action), config.name); #endif @@ -1342,7 +1406,7 @@ std::shared_ptr getRemoteLogAction(const RemoteLogActionConfig } } dnsdist::actions::ProtobufAlterFunction alterFunc; - if (dnsdist::configuration::yaml::getOptionalLuaFunction(alterFunc, config.alter_function)) { + if (dnsdist::configuration::yaml::getLuaFunctionFromConfiguration(alterFunc, config.alter_function_name, config.alter_function_code, config.alter_function_file, "remote log action")) { actionConfig.alterQueryFunc = std::move(alterFunc); } auto action = dnsdist::actions::getRemoteLogAction(actionConfig); @@ -1377,7 +1441,7 @@ std::shared_ptr getRemoteLogResponseAction(const Remot actionConfig.exportExtendedErrorsToMeta = std::string(config.export_extended_errors_to_meta); } dnsdist::actions::ProtobufAlterResponseFunction alterFunc; - if (dnsdist::configuration::yaml::getOptionalLuaFunction(alterFunc, config.alter_function)) { + if (dnsdist::configuration::yaml::getLuaFunctionFromConfiguration(alterFunc, config.alter_function_name, config.alter_function_code, config.alter_function_file, "remote log response action")) { actionConfig.alterResponseFunc = std::move(alterFunc); } auto action = dnsdist::actions::getRemoteLogResponseAction(actionConfig); @@ -1471,6 +1535,26 @@ void registerKVSObjects(const KeyValueStoresConfiguration& config) #endif /* defined(HAVE_LMDB) || defined(HAVE_CDB) */ } +std::shared_ptr getLuaSelector(const LuaSelectorConfiguration& config) +{ + dnsdist::selectors::LuaSelectorFunction function; + if (!dnsdist::configuration::yaml::getLuaFunctionFromConfiguration(function, config.function_name, config.function_code, config.function_file, "Lua selector")) { + throw std::runtime_error("Unable to create a Lua selector: no valid function name, Lua code or Lua file"); + } + auto selector = dnsdist::selectors::getLuaSelector(function); + return newDNSSelector(std::move(selector), config.name); +} + +std::shared_ptr getLuaFFISelector(const LuaFFISelectorConfiguration& config) +{ + dnsdist::selectors::LuaSelectorFFIFunction function; + if (!dnsdist::configuration::yaml::getLuaFunctionFromConfiguration(function, config.function_name, config.function_code, config.function_file, "Lua FFI selector")) { + throw std::runtime_error("Unable to create a Lua FFI selector: no valid function name, Lua code or Lua file"); + } + auto selector = dnsdist::selectors::getLuaFFISelector(function); + return newDNSSelector(std::move(selector), config.name); +} + std::shared_ptr getAndSelector(const AndSelectorConfiguration& config) { std::vector> selectors; diff --git a/pdns/dnsdistdist/dnsdist-lua-actions-generated.cc b/pdns/dnsdistdist/dnsdist-lua-actions-generated.cc index 512391972c..2a4f143440 100644 --- a/pdns/dnsdistdist/dnsdist-lua-actions-generated.cc +++ b/pdns/dnsdistdist/dnsdist-lua-actions-generated.cc @@ -14,12 +14,6 @@ luaCtx.writeFunction("SetEDNSOptionAction", [](uint32_t code, std::string data) luaCtx.writeFunction("LogAction", [](boost::optional fileName, boost::optional binary, boost::optional append, boost::optional buffered, boost::optional verboseOnly, boost::optional includeTimestamp) { return dnsdist::actions::getLogAction(fileName ? *fileName : "", binary ? *binary : true, append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false); }); -luaCtx.writeFunction("LuaAction", [](dnsdist::actions::LuaActionFunction function) { - return dnsdist::actions::getLuaAction(function); -}); -luaCtx.writeFunction("LuaFFIAction", [](dnsdist::actions::LuaActionFFIFunction function) { - return dnsdist::actions::getLuaFFIAction(function); -}); luaCtx.writeFunction("LuaFFIPerThreadAction", [](std::string code) { return dnsdist::actions::getLuaFFIPerThreadAction(code); }); diff --git a/pdns/dnsdistdist/dnsdist-lua-actions.cc b/pdns/dnsdistdist/dnsdist-lua-actions.cc index f35246ceba..5015bed073 100644 --- a/pdns/dnsdistdist/dnsdist-lua-actions.cc +++ b/pdns/dnsdistdist/dnsdist-lua-actions.cc @@ -137,6 +137,22 @@ void setupLuaActions(LuaContext& luaCtx) luaCtx.registerFunction("reload", &DNSAction::reload); luaCtx.registerFunction("reload", &DNSResponseAction::reload); + luaCtx.writeFunction("LuaAction", [](dnsdist::actions::LuaActionFunction function) { + return dnsdist::actions::getLuaAction(function); + }); + + luaCtx.writeFunction("LuaFFIAction", [](dnsdist::actions::LuaActionFFIFunction function) { + return dnsdist::actions::getLuaFFIAction(function); + }); + + luaCtx.writeFunction("LuaResponseAction", [](dnsdist::actions::LuaResponseActionFunction function) { + return dnsdist::actions::getLuaResponseAction(function); + }); + + luaCtx.writeFunction("LuaFFIResponseAction", [](dnsdist::actions::LuaResponseActionFFIFunction function) { + return dnsdist::actions::getLuaFFIResponseAction(function); + }); + luaCtx.writeFunction("SpoofAction", [](LuaTypeOrArrayOf inp, boost::optional vars) { vector addrs; if (auto* ipaddr = boost::get(&inp)) { diff --git a/pdns/dnsdistdist/dnsdist-lua-response-actions-generated.cc b/pdns/dnsdistdist/dnsdist-lua-response-actions-generated.cc index bc5a13ba7c..b6cfa242b6 100644 --- a/pdns/dnsdistdist/dnsdist-lua-response-actions-generated.cc +++ b/pdns/dnsdistdist/dnsdist-lua-response-actions-generated.cc @@ -11,12 +11,6 @@ luaCtx.writeFunction("DropResponseAction", []() { luaCtx.writeFunction("LogResponseAction", [](boost::optional fileName, boost::optional append, boost::optional buffered, boost::optional verboseOnly, boost::optional includeTimestamp) { return dnsdist::actions::getLogResponseAction(fileName ? *fileName : "", append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false); }); -luaCtx.writeFunction("LuaResponseAction", [](dnsdist::actions::LuaResponseActionFunction function) { - return dnsdist::actions::getLuaResponseAction(function); -}); -luaCtx.writeFunction("LuaFFIResponseAction", [](dnsdist::actions::LuaResponseActionFFIFunction function) { - return dnsdist::actions::getLuaFFIResponseAction(function); -}); luaCtx.writeFunction("LuaFFIPerThreadResponseAction", [](std::string code) { return dnsdist::actions::getLuaFFIPerThreadResponseAction(code); }); diff --git a/pdns/dnsdistdist/dnsdist-lua-rules.cc b/pdns/dnsdistdist/dnsdist-lua-rules.cc index 8709a2eb15..52468bce21 100644 --- a/pdns/dnsdistdist/dnsdist-lua-rules.cc +++ b/pdns/dnsdistdist/dnsdist-lua-rules.cc @@ -576,6 +576,14 @@ void setupLuaRules(LuaContext& luaCtx) return std::shared_ptr(new NotRule(rule)); }); + luaCtx.writeFunction("LuaRule", [](dnsdist::selectors::LuaSelectorFunction function) { + return std::shared_ptr(dnsdist::selectors::getLuaSelector(function)); + }); + + luaCtx.writeFunction("LuaFFIRule", [](dnsdist::selectors::LuaSelectorFFIFunction function) { + return std::shared_ptr(dnsdist::selectors::getLuaFFISelector(function)); + }); + luaCtx.writeFunction("RCodeRule", [](uint64_t rcode) { checkParameterBound("RCodeRule", rcode, std::numeric_limits::max()); return std::shared_ptr(new RCodeRule(rcode)); diff --git a/pdns/dnsdistdist/dnsdist-lua-selectors-generated.cc b/pdns/dnsdistdist/dnsdist-lua-selectors-generated.cc index d16d9050d4..bb870cfdd7 100644 --- a/pdns/dnsdistdist/dnsdist-lua-selectors-generated.cc +++ b/pdns/dnsdistdist/dnsdist-lua-selectors-generated.cc @@ -26,12 +26,6 @@ luaCtx.writeFunction("HTTPPathRule", [](std::string path) { luaCtx.writeFunction("HTTPPathRegexRule", [](std::string expression) { return std::shared_ptr(dnsdist::selectors::getHTTPPathRegexSelector(expression)); }); -luaCtx.writeFunction("LuaRule", [](dnsdist::selectors::LuaSelectorFunction function) { - return std::shared_ptr(dnsdist::selectors::getLuaSelector(function)); -}); -luaCtx.writeFunction("LuaFFIRule", [](dnsdist::selectors::LuaSelectorFFIFunction function) { - return std::shared_ptr(dnsdist::selectors::getLuaFFISelector(function)); -}); luaCtx.writeFunction("LuaFFIPerThreadRule", [](std::string code) { return std::shared_ptr(dnsdist::selectors::getLuaFFIPerThreadSelector(code)); }); diff --git a/pdns/dnsdistdist/dnsdist-lua.hh b/pdns/dnsdistdist/dnsdist-lua.hh index b6e44b9809..09d18a643b 100644 --- a/pdns/dnsdistdist/dnsdist-lua.hh +++ b/pdns/dnsdistdist/dnsdist-lua.hh @@ -66,6 +66,23 @@ namespace dnsdist::lua { void setupLua(LuaContext& luaCtx, bool client, bool configCheck); void setupConfigurationItems(LuaContext& luaCtx); + +template +std::optional getFunctionFromLuaCode(const std::string& code, const std::string& context) +{ + try { + auto function = g_lua.lock()->executeCode(code); + if (!function) { + return std::nullopt; + } + return function; + } + catch (const std::exception& exp) { + warnlog("Parsing Lua code '%s' in context '%s' failed: %s", code, context, exp.what()); + } + + return std::nullopt; +} } namespace dnsdist::configuration::lua diff --git a/pdns/dnsdistdist/dnsdist-response-actions-definitions.yml b/pdns/dnsdistdist/dnsdist-response-actions-definitions.yml index a7553ce917..45a2d420c6 100644 --- a/pdns/dnsdistdist/dnsdist-response-actions-definitions.yml +++ b/pdns/dnsdistdist/dnsdist-response-actions-definitions.yml @@ -24,9 +24,14 @@ type: "String" - name: "logger-name" type: "String" - - name: "alter-function" - type: "dnsdist::actions::DnstapAlterResponseFunction" - rust-type: "String" + - name: "alter-function_name" + type: "String" + default: "" + - name: "alter-function-code" + type: "String" + default: "" + - name: "alter-function-file" + type: "String" default: "" - name: "drop" description: "Drop the packet" @@ -70,16 +75,32 @@ Subsequent rules are processed after this action" cpp-optional: false - name: "lua" description: "Invoke a Lua function that accepts a :class:`DNSResponse`. The function should return a :ref:`DNSResponseAction`. If the Lua code fails, ``ServFail`` is returned" + skip-cpp: true + skip-rust: true parameters: - - name: "function" - type: "dnsdist::actions::LuaResponseActionFunction" - rust-type: "String" + - name: "function-name" + type: "String" + default: "" + - name: "function-code" + type: "String" + default: "" + - name: "function-file" + type: "String" + default: "" - name: "LuaFFI" description: "Invoke a Lua function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``. The function should return a :ref:`DNSResponseAction`. If the Lua code fails, ``ServFail`` is returned" + skip-cpp: true + skip-rust: true parameters: - - name: "function" - type: "dnsdist::actions::LuaResponseActionFFIFunction" - rust-type: "String" + - name: "function-name" + type: "String" + default: "" + - name: "function-code" + type: "String" + default: "" + - name: "function-file" + type: "String" + default: "" - name: "LuaFFIPerThread" description: "Invoke a Lua function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``. The function should return a :ref:`DNSResponseAction`. If the Lua code fails, ``ServFail`` is returned. The function will be invoked in a per-thread Lua state, without access to the global Lua state. All constants (:ref:`DNSQType`, :ref:`DNSRCode`, ...) are available in that per-thread context, as well as all FFI functions. Objects and their bindings that are not usable in a FFI context (:class:`DNSQuestion`, :class:`DNSDistProtoBufMessage`, :class:`PacketCache`, ...) are not available." @@ -93,9 +114,14 @@ The function will be invoked in a per-thread Lua state, without access to the gl parameters: - name: "logger-name" type: "String" - - name: "alter-function" - type: "dnsdist::actions::ProtobufAlterResponseFunction" - rust-type: "String" + - name: "alter-function-name" + type: "String" + default: "" + - name: "alter-function-code" + type: "String" + default: "" + - name: "alter-function-file" + type: "String" default: "" - name: "server-id" type: "String" diff --git a/pdns/dnsdistdist/dnsdist-response-actions-factory-generated.cc b/pdns/dnsdistdist/dnsdist-response-actions-factory-generated.cc index 3066ffb12d..b02eb932bc 100644 --- a/pdns/dnsdistdist/dnsdist-response-actions-factory-generated.cc +++ b/pdns/dnsdistdist/dnsdist-response-actions-factory-generated.cc @@ -15,14 +15,6 @@ std::shared_ptr getLogResponseAction(const std::string& fileN { return std::shared_ptr(new LogResponseAction(fileName, append, buffered, verboseOnly, includeTimestamp)); } -std::shared_ptr getLuaResponseAction(dnsdist::actions::LuaResponseActionFunction function) -{ - return std::shared_ptr(new LuaResponseAction(function)); -} -std::shared_ptr getLuaFFIResponseAction(dnsdist::actions::LuaResponseActionFFIFunction function) -{ - return std::shared_ptr(new LuaFFIResponseAction(function)); -} std::shared_ptr getLuaFFIPerThreadResponseAction(const std::string& code) { return std::shared_ptr(new LuaFFIPerThreadResponseAction(code)); diff --git a/pdns/dnsdistdist/dnsdist-response-actions-factory-generated.hh b/pdns/dnsdistdist/dnsdist-response-actions-factory-generated.hh index 839dbaf86b..5858bf61c6 100644 --- a/pdns/dnsdistdist/dnsdist-response-actions-factory-generated.hh +++ b/pdns/dnsdistdist/dnsdist-response-actions-factory-generated.hh @@ -3,8 +3,6 @@ std::shared_ptr getAllowResponseAction(); std::shared_ptr getDelayResponseAction(uint32_t msec); std::shared_ptr getDropResponseAction(); std::shared_ptr getLogResponseAction(const std::string& fileName, bool append, bool buffered, bool verboseOnly, bool includeTimestamp); -std::shared_ptr getLuaResponseAction(dnsdist::actions::LuaResponseActionFunction function); -std::shared_ptr getLuaFFIResponseAction(dnsdist::actions::LuaResponseActionFFIFunction function); std::shared_ptr getLuaFFIPerThreadResponseAction(const std::string& code); std::shared_ptr getSetExtendedDNSErrorResponseAction(uint16_t infoCode, const std::string& extraText); std::shared_ptr getSetReducedTTLResponseAction(uint8_t percentage); diff --git a/pdns/dnsdistdist/dnsdist-rules-factory.hh b/pdns/dnsdistdist/dnsdist-rules-factory.hh index 08711f6fe8..ccec8356b6 100644 --- a/pdns/dnsdistdist/dnsdist-rules-factory.hh +++ b/pdns/dnsdistdist/dnsdist-rules-factory.hh @@ -1499,6 +1499,8 @@ namespace dnsdist::selectors std::shared_ptr getAndSelector(const std::vector>& rules); std::shared_ptr getOrSelector(const std::vector>& rules); std::shared_ptr getNotSelector(const std::shared_ptr& rule); +std::shared_ptr getLuaSelector(const dnsdist::selectors::LuaSelectorFunction& func); +std::shared_ptr getLuaFFISelector(const dnsdist::selectors::LuaSelectorFFIFunction& func); std::shared_ptr getQNameSelector(const DNSName& qname); std::shared_ptr getQNameSetSelector(const DNSNameSet& qnames); std::shared_ptr getQNameSuffixSelector(const SuffixMatchNode& suffixes, bool quiet); diff --git a/pdns/dnsdistdist/dnsdist-rules-generator.py b/pdns/dnsdistdist/dnsdist-rules-generator.py index cb6c0d73f8..7a92c0f983 100644 --- a/pdns/dnsdistdist/dnsdist-rules-generator.py +++ b/pdns/dnsdistdist/dnsdist-rules-generator.py @@ -28,7 +28,7 @@ # special unquoted true value which means to use the default value for the # object type, which needs to exist. # Items can optionally have the following properties: -# - 'skip-cpp' means that the corresponding C++ factory and Lua bindinds will not be generated, which is useful for objects taking parameters that cannot be directly mapped +# - 'skip-cpp' means that the corresponding C++ factory and Lua bindings will not be generated, which is useful for objects taking parameters that cannot be directly mapped # - 'skip-rust' is not used by this script but is used by the dnsdist-settings-generator.py one, where it means that the C++ code to create the Rust-side version of an action or selector will not generated # - 'skip-serde' is not used by this script but is used by the dnsdist-settings-generator.py one, where it means that the Rust structure representing that action or selector in the YAML setting will not be directly created by Serde. It is used for selectors that reference another selector themselves, or actions referencing another action. import os diff --git a/pdns/dnsdistdist/dnsdist-rules.cc b/pdns/dnsdistdist/dnsdist-rules.cc index e4904fdca1..5b97eba9d2 100644 --- a/pdns/dnsdistdist/dnsdist-rules.cc +++ b/pdns/dnsdistdist/dnsdist-rules.cc @@ -191,6 +191,16 @@ std::shared_ptr getNotSelector(const std::shared_ptr& rule) return std::make_shared(rule); } +std::shared_ptr getLuaSelector(const dnsdist::selectors::LuaSelectorFunction& func) +{ + return std::make_shared(func); +} + +std::shared_ptr getLuaFFISelector(const dnsdist::selectors::LuaSelectorFFIFunction& func) +{ + return std::make_shared(func); +} + // NOLINTNEXTLINE(bugprone-suspicious-include) #include "dnsdist-selectors-factory-generated.cc" diff --git a/pdns/dnsdistdist/dnsdist-rust-bridge-actions-generated.cc b/pdns/dnsdistdist/dnsdist-rust-bridge-actions-generated.cc index 3204c13232..6bce7dab5a 100644 --- a/pdns/dnsdistdist/dnsdist-rust-bridge-actions-generated.cc +++ b/pdns/dnsdistdist/dnsdist-rust-bridge-actions-generated.cc @@ -34,16 +34,6 @@ std::shared_ptr getLogAction(const LogActionConfiguration& con auto action = dnsdist::actions::getLogAction(std::string(config.file_name), config.binary, config.append, config.buffered, config.verbose_only, config.include_timestamp); return newDNSActionWrapper(std::move(action), config.name); } -std::shared_ptr getLuaAction(const LuaActionConfiguration& config) -{ - auto action = dnsdist::actions::getLuaAction(convertLuaFunction("LuaActionConfiguration", config.function)); - return newDNSActionWrapper(std::move(action), config.name); -} -std::shared_ptr getLuaFFIAction(const LuaFFIActionConfiguration& config) -{ - auto action = dnsdist::actions::getLuaFFIAction(convertLuaFunction("LuaFFIActionConfiguration", config.function)); - return newDNSActionWrapper(std::move(action), config.name); -} std::shared_ptr getLuaFFIPerThreadAction(const LuaFFIPerThreadActionConfiguration& config) { auto action = dnsdist::actions::getLuaFFIPerThreadAction(std::string(config.code)); @@ -184,16 +174,6 @@ std::shared_ptr getLogResponseAction(const LogResponse auto action = dnsdist::actions::getLogResponseAction(std::string(config.file_name), config.append, config.buffered, config.verbose_only, config.include_timestamp); return newDNSResponseActionWrapper(std::move(action), config.name); } -std::shared_ptr getLuaResponseAction(const LuaResponseActionConfiguration& config) -{ - auto action = dnsdist::actions::getLuaResponseAction(convertLuaFunction("LuaResponseActionConfiguration", config.function)); - return newDNSResponseActionWrapper(std::move(action), config.name); -} -std::shared_ptr getLuaFFIResponseAction(const LuaFFIResponseActionConfiguration& config) -{ - auto action = dnsdist::actions::getLuaFFIResponseAction(convertLuaFunction("LuaFFIResponseActionConfiguration", config.function)); - return newDNSResponseActionWrapper(std::move(action), config.name); -} std::shared_ptr getLuaFFIPerThreadResponseAction(const LuaFFIPerThreadResponseActionConfiguration& config) { auto action = dnsdist::actions::getLuaFFIPerThreadResponseAction(std::string(config.code)); diff --git a/pdns/dnsdistdist/dnsdist-rust-bridge-selectors-generated.cc b/pdns/dnsdistdist/dnsdist-rust-bridge-selectors-generated.cc index 8ae735d51b..fad3bc9952 100644 --- a/pdns/dnsdistdist/dnsdist-rust-bridge-selectors-generated.cc +++ b/pdns/dnsdistdist/dnsdist-rust-bridge-selectors-generated.cc @@ -44,16 +44,6 @@ std::shared_ptr getHTTPPathRegexSelector(const HTTPPathRegexSelecto auto selector = dnsdist::selectors::getHTTPPathRegexSelector(std::string(config.expression)); return newDNSSelector(std::move(selector), config.name); } -std::shared_ptr getLuaSelector(const LuaSelectorConfiguration& config) -{ - auto selector = dnsdist::selectors::getLuaSelector(convertLuaFunction("LuaSelectorConfiguration", config.function)); - return newDNSSelector(std::move(selector), config.name); -} -std::shared_ptr getLuaFFISelector(const LuaFFISelectorConfiguration& config) -{ - auto selector = dnsdist::selectors::getLuaFFISelector(convertLuaFunction("LuaFFISelectorConfiguration", config.function)); - return newDNSSelector(std::move(selector), config.name); -} std::shared_ptr getLuaFFIPerThreadSelector(const LuaFFIPerThreadSelectorConfiguration& config) { auto selector = dnsdist::selectors::getLuaFFIPerThreadSelector(std::string(config.code)); diff --git a/pdns/dnsdistdist/dnsdist-rust-lib/dnsdist-settings-generator.py b/pdns/dnsdistdist/dnsdist-rust-lib/dnsdist-settings-generator.py index f9a7fe8a5f..b9d4a78135 100644 --- a/pdns/dnsdistdist/dnsdist-rust-lib/dnsdist-settings-generator.py +++ b/pdns/dnsdistdist/dnsdist-rust-lib/dnsdist-settings-generator.py @@ -496,8 +496,6 @@ def get_cpp_parameters(struct_type, struct_name, parameters, skip_name): field = f'convertSVCRecordParameters({field})' elif ptype == 'SOAParams': field = f'convertSOAParams({field})' - elif ptype in ['dnsdist::actions::LuaActionFunction', 'dnsdist::actions::LuaActionFFIFunction', 'dnsdist::actions::LuaResponseActionFunction', 'dnsdist::actions::LuaResponseActionFFIFunction', 'dnsdist::selectors::LuaSelectorFunction', 'dnsdist::selectors::LuaSelectorFFIFunction']: - field = f'convertLuaFunction<{ptype}>("{struct_type}", {field})' output += field return output diff --git a/pdns/dnsdistdist/dnsdist-rust-lib/rust/src/lib.rs b/pdns/dnsdistdist/dnsdist-rust-lib/rust/src/lib.rs index f975c906a6..6353236c8c 100644 --- a/pdns/dnsdistdist/dnsdist-rust-lib/rust/src/lib.rs +++ b/pdns/dnsdistdist/dnsdist-rust-lib/rust/src/lib.rs @@ -112,8 +112,12 @@ mod dnsdistsettings { identity: String, #[serde(rename = "logger-name", )] logger_name: String, - #[serde(rename = "alter-function", default, skip_serializing_if = "crate::is_default")] - alter_function: String, + #[serde(rename = "alter-function-name", default, skip_serializing_if = "crate::is_default")] + alter_function_name: String, + #[serde(rename = "alter-function-code", default, skip_serializing_if = "crate::is_default")] + alter_function_code: String, + #[serde(rename = "alter-function-file", default, skip_serializing_if = "crate::is_default")] + alter_function_file: String, } #[derive(Deserialize, Serialize, Debug, PartialEq)] @@ -205,7 +209,12 @@ mod dnsdistsettings { struct LuaActionConfiguration { #[serde(default, skip_serializing_if = "crate::is_default")] name: String, - function: String, + #[serde(rename = "function-name", default, skip_serializing_if = "crate::is_default")] + function_name: String, + #[serde(rename = "function-code", default, skip_serializing_if = "crate::is_default")] + function_code: String, + #[serde(rename = "function-file", default, skip_serializing_if = "crate::is_default")] + function_file: String, } #[derive(Deserialize, Serialize, Debug, PartialEq)] @@ -213,7 +222,12 @@ mod dnsdistsettings { struct LuaFFIActionConfiguration { #[serde(default, skip_serializing_if = "crate::is_default")] name: String, - function: String, + #[serde(rename = "function-name", default, skip_serializing_if = "crate::is_default")] + function_name: String, + #[serde(rename = "function-code", default, skip_serializing_if = "crate::is_default")] + function_code: String, + #[serde(rename = "function-file", default, skip_serializing_if = "crate::is_default")] + function_file: String, } #[derive(Deserialize, Serialize, Debug, PartialEq)] @@ -297,8 +311,12 @@ mod dnsdistsettings { name: String, #[serde(rename = "logger-name", )] logger_name: String, - #[serde(rename = "alter-function", default, skip_serializing_if = "crate::is_default")] - alter_function: String, + #[serde(rename = "alter-function-name", default, skip_serializing_if = "crate::is_default")] + alter_function_name: String, + #[serde(rename = "alter-function-code", default, skip_serializing_if = "crate::is_default")] + alter_function_code: String, + #[serde(rename = "alter-function-file", default, skip_serializing_if = "crate::is_default")] + alter_function_file: String, #[serde(rename = "server-id", default, skip_serializing_if = "crate::is_default")] server_id: String, #[serde(rename = "ip-encrypt-key", default, skip_serializing_if = "crate::is_default")] @@ -542,8 +560,12 @@ mod dnsdistsettings { identity: String, #[serde(rename = "logger-name", )] logger_name: String, - #[serde(rename = "alter-function", default, skip_serializing_if = "crate::is_default")] - alter_function: String, + #[serde(rename = "alter-function_name", default, skip_serializing_if = "crate::is_default")] + alter_function_name: String, + #[serde(rename = "alter-function-code", default, skip_serializing_if = "crate::is_default")] + alter_function_code: String, + #[serde(rename = "alter-function-file", default, skip_serializing_if = "crate::is_default")] + alter_function_file: String, } #[derive(Deserialize, Serialize, Debug, PartialEq)] @@ -586,7 +608,12 @@ mod dnsdistsettings { struct LuaResponseActionConfiguration { #[serde(default, skip_serializing_if = "crate::is_default")] name: String, - function: String, + #[serde(rename = "function-name", default, skip_serializing_if = "crate::is_default")] + function_name: String, + #[serde(rename = "function-code", default, skip_serializing_if = "crate::is_default")] + function_code: String, + #[serde(rename = "function-file", default, skip_serializing_if = "crate::is_default")] + function_file: String, } #[derive(Deserialize, Serialize, Debug, PartialEq)] @@ -594,7 +621,12 @@ mod dnsdistsettings { struct LuaFFIResponseActionConfiguration { #[serde(default, skip_serializing_if = "crate::is_default")] name: String, - function: String, + #[serde(rename = "function-name", default, skip_serializing_if = "crate::is_default")] + function_name: String, + #[serde(rename = "function-code", default, skip_serializing_if = "crate::is_default")] + function_code: String, + #[serde(rename = "function-file", default, skip_serializing_if = "crate::is_default")] + function_file: String, } #[derive(Deserialize, Serialize, Debug, PartialEq)] @@ -612,8 +644,12 @@ mod dnsdistsettings { name: String, #[serde(rename = "logger-name", )] logger_name: String, - #[serde(rename = "alter-function", default, skip_serializing_if = "crate::is_default")] - alter_function: String, + #[serde(rename = "alter-function-name", default, skip_serializing_if = "crate::is_default")] + alter_function_name: String, + #[serde(rename = "alter-function-code", default, skip_serializing_if = "crate::is_default")] + alter_function_code: String, + #[serde(rename = "alter-function-file", default, skip_serializing_if = "crate::is_default")] + alter_function_file: String, #[serde(rename = "server-id", default, skip_serializing_if = "crate::is_default")] server_id: String, #[serde(rename = "ip-encrypt-key", default, skip_serializing_if = "crate::is_default")] @@ -817,7 +853,12 @@ mod dnsdistsettings { struct LuaSelectorConfiguration { #[serde(default, skip_serializing_if = "crate::is_default")] name: String, - function: String, + #[serde(rename = "function-name", default, skip_serializing_if = "crate::is_default")] + function_name: String, + #[serde(rename = "function-code", default, skip_serializing_if = "crate::is_default")] + function_code: String, + #[serde(rename = "function-file", default, skip_serializing_if = "crate::is_default")] + function_file: String, } #[derive(Deserialize, Serialize, Debug, PartialEq)] @@ -825,7 +866,12 @@ mod dnsdistsettings { struct LuaFFISelectorConfiguration { #[serde(default, skip_serializing_if = "crate::is_default")] name: String, - function: String, + #[serde(rename = "function-name", default, skip_serializing_if = "crate::is_default")] + function_name: String, + #[serde(rename = "function-code", default, skip_serializing_if = "crate::is_default")] + function_code: String, + #[serde(rename = "function-file", default, skip_serializing_if = "crate::is_default")] + function_file: String, } #[derive(Deserialize, Serialize, Debug, PartialEq)] @@ -1407,8 +1453,12 @@ mod dnsdistsettings { tag_name: String, #[serde(rename = "tag-value", default = "crate::default_value_dynamic_rule_tag_value", skip_serializing_if = "crate::default_value_equal_dynamic_rule_tag_value")] tag_value: String, - #[serde(rename = "visitor-function", default, skip_serializing_if = "crate::is_default")] - visitor_function: String, + #[serde(rename = "visitor-function-name", default, skip_serializing_if = "crate::is_default")] + visitor_function_name: String, + #[serde(rename = "visitor-function-code", default, skip_serializing_if = "crate::is_default")] + visitor_function_code: String, + #[serde(rename = "visitor-function-file", default, skip_serializing_if = "crate::is_default")] + visitor_function_file: String, #[serde(default, skip_serializing_if = "crate::is_default")] rcode: String, #[serde(default, skip_serializing_if = "crate::is_default")] @@ -1728,6 +1778,10 @@ mod dnsdistsettings { qtype: String, #[serde(default, skip_serializing_if = "crate::is_default")] function: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + lua: String, + #[serde(rename = "lua-file", default, skip_serializing_if = "crate::is_default")] + lua_file: String, #[serde(default = "crate::U16::<1000>::value", skip_serializing_if = "crate::U16::<1000>::is_equal")] timeout: u16, #[serde(rename = "set-cd", default, skip_serializing_if = "crate::is_default")] @@ -2014,8 +2068,12 @@ mod dnsdistsettings { struct QueryCountConfiguration { #[serde(default, skip_serializing_if = "crate::is_default")] enabled: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - filter: String, + #[serde(rename = "filter-function-name", default, skip_serializing_if = "crate::is_default")] + filter_function_name: String, + #[serde(rename = "filter-function-code", default, skip_serializing_if = "crate::is_default")] + filter_function_code: String, + #[serde(rename = "filter-function-file", default, skip_serializing_if = "crate::is_default")] + filter_function_file: String, } #[derive(Deserialize, Serialize, Debug, PartialEq)] @@ -2032,7 +2090,12 @@ mod dnsdistsettings { #[serde(deny_unknown_fields)] struct CustomLoadBalancingPolicyConfiguration { name: String, - function: String, + #[serde(rename = "function-name", default, skip_serializing_if = "crate::is_default")] + function_name: String, + #[serde(rename = "function-code", default, skip_serializing_if = "crate::is_default")] + function_code: String, + #[serde(rename = "function-file", default, skip_serializing_if = "crate::is_default")] + function_file: String, #[serde(default, skip_serializing_if = "crate::is_default")] ffi: bool, #[serde(rename = "per-thread", default, skip_serializing_if = "crate::is_default")] diff --git a/pdns/dnsdistdist/dnsdist-selectors-definitions.yml b/pdns/dnsdistdist/dnsdist-selectors-definitions.yml index 7f6c9ede29..182cbad8c8 100644 --- a/pdns/dnsdistdist/dnsdist-selectors-definitions.yml +++ b/pdns/dnsdistdist/dnsdist-selectors-definitions.yml @@ -78,16 +78,32 @@ This assumes that there is a key, in network byte order, for the last element of type: "String" - name: "lua" description: "Invoke a Lua function that accepts a :class:`DNSQuestion` object. The function should return true if the query matches, or false otherwise. If the Lua code fails, false is returned" + skip-cpp: true + skip-rust: true parameters: - - name: "function" - type: "dnsdist::selectors::LuaSelectorFunction" - rust-type: "String" + - name: "function-name" + type: "String" + default: "" + - name: "function-code" + type: "String" + default: "" + - name: "function-file" + type: "String" + default: "" - name: "LuaFFI" description: "Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``. The function should return true if the query matches, or false otherwise. If the Lua code fails, false is returned" + skip-cpp: true + skip-rust: true parameters: - - name: "function" - type: "dnsdist::selectors::LuaSelectorFFIFunction" - rust-type: "String" + - name: "function-name" + type: "String" + default: "" + - name: "function-code" + type: "String" + default: "" + - name: "function-file" + type: "String" + default: "" - name: "LuaFFIPerThread" description: "Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``. The function should return true if the query matches, or false otherwise. If the Lua code fails, false is returned. diff --git a/pdns/dnsdistdist/dnsdist-selectors-factory-generated.cc b/pdns/dnsdistdist/dnsdist-selectors-factory-generated.cc index 224ff58f42..01894a8cab 100644 --- a/pdns/dnsdistdist/dnsdist-selectors-factory-generated.cc +++ b/pdns/dnsdistdist/dnsdist-selectors-factory-generated.cc @@ -35,14 +35,6 @@ std::shared_ptr getHTTPPathRegexSelector(const std::string& e { return std::make_shared(expression); } -std::shared_ptr getLuaSelector(dnsdist::selectors::LuaSelectorFunction function) -{ - return std::make_shared(function); -} -std::shared_ptr getLuaFFISelector(dnsdist::selectors::LuaSelectorFFIFunction function) -{ - return std::make_shared(function); -} std::shared_ptr getLuaFFIPerThreadSelector(const std::string& code) { return std::make_shared(code); diff --git a/pdns/dnsdistdist/dnsdist-selectors-factory-generated.hh b/pdns/dnsdistdist/dnsdist-selectors-factory-generated.hh index fe48132d47..bf4b579393 100644 --- a/pdns/dnsdistdist/dnsdist-selectors-factory-generated.hh +++ b/pdns/dnsdistdist/dnsdist-selectors-factory-generated.hh @@ -8,8 +8,6 @@ std::shared_ptr getERCodeSelector(uint64_t rcode); std::shared_ptr getHTTPHeaderSelector(const std::string& header, const std::string& expression); std::shared_ptr getHTTPPathSelector(const std::string& path); std::shared_ptr getHTTPPathRegexSelector(const std::string& expression); -std::shared_ptr getLuaSelector(dnsdist::selectors::LuaSelectorFunction function); -std::shared_ptr getLuaFFISelector(dnsdist::selectors::LuaSelectorFFIFunction function); std::shared_ptr getLuaFFIPerThreadSelector(const std::string& code); std::shared_ptr getMaxQPSSelector(uint32_t qps, std::optional burst); std::shared_ptr getMaxQPSIPSelector(uint32_t qps, std::optional ipv4Mask, std::optional ipv6Mask, std::optional burst, std::optional expiration, std::optional cleanupDelay, std::optional scanFraction, std::optional shards); diff --git a/pdns/dnsdistdist/dnsdist-settings-definitions.yml b/pdns/dnsdistdist/dnsdist-settings-definitions.yml index 25910f860e..821ace3017 100644 --- a/pdns/dnsdistdist/dnsdist-settings-definitions.yml +++ b/pdns/dnsdistdist/dnsdist-settings-definitions.yml @@ -498,7 +498,13 @@ dynamic-rule: - name: "tag-value" type: "String" default: "0" - - name: "visitor-function" + - name: "visitor-function-name" + type: "String" + default: "" + - name: "visitor-function-code" + type: "String" + default: "" + - name: "visitor-function-file" type: "String" default: "" - name: "rcode" @@ -920,6 +926,12 @@ health-check: - name: "function" type: "String" default: "" + - name: "lua" + type: "String" + default: "" + - name: "lua-file" + type: "String" + default: "" - name: "timeout" type: "u16" default: 1000 @@ -1425,7 +1437,13 @@ query-count: - name: "enabled" type: "bool" default: "false" - - name: "filter" + - name: "filter-function-name" + type: "String" + default: "" + - name: "filter-function-code" + type: "String" + default: "" + - name: "filter-function-file" type: "String" default: "" @@ -1444,8 +1462,15 @@ custom-load-balancing-policy: parameters: - name: "name" type: "String" - - name: "function" + - name: "function-name" type: "String" + default: "" + - name: "function-code" + type: "String" + default: "" + - name: "function-file" + type: "String" + default: "" - name: "ffi" type: "bool" default: "false" diff --git a/pdns/dnsdistdist/docs/reference/yaml-actions.rst b/pdns/dnsdistdist/docs/reference/yaml-actions.rst index 2b64625f71..30dd7d1acb 100644 --- a/pdns/dnsdistdist/docs/reference/yaml-actions.rst +++ b/pdns/dnsdistdist/docs/reference/yaml-actions.rst @@ -59,7 +59,9 @@ Parameters: - **identity**: String - **logger-name**: String -- **alter-function**: String ``("")`` +- **alter-function-name**: String ``("")`` +- **alter-function-code**: String ``("")`` +- **alter-function-file**: String ``("")`` .. _yaml-settings-DropAction: @@ -180,7 +182,9 @@ Lua equivalent: :func:`LuaAction` Parameters: -- **function**: String +- **function-name**: String ``("")`` +- **function-code**: String ``("")`` +- **function-file**: String ``("")`` .. _yaml-settings-LuaFFIAction: @@ -194,7 +198,9 @@ Lua equivalent: :func:`LuaFFIAction` Parameters: -- **function**: String +- **function-name**: String ``("")`` +- **function-code**: String ``("")`` +- **function-file**: String ``("")`` .. _yaml-settings-LuaFFIPerThreadAction: @@ -313,7 +319,9 @@ Lua equivalent: :func:`RemoteLogAction` Parameters: - **logger-name**: String -- **alter-function**: String ``("")`` +- **alter-function-name**: String ``("")`` +- **alter-function-code**: String ``("")`` +- **alter-function-file**: String ``("")`` - **server-id**: String ``("")`` - **ip-encrypt-key**: String ``("")`` - **export-tags**: Sequence of String diff --git a/pdns/dnsdistdist/docs/reference/yaml-response-actions.rst b/pdns/dnsdistdist/docs/reference/yaml-response-actions.rst index 34e2f88488..db91181e26 100644 --- a/pdns/dnsdistdist/docs/reference/yaml-response-actions.rst +++ b/pdns/dnsdistdist/docs/reference/yaml-response-actions.rst @@ -59,7 +59,9 @@ Parameters: - **identity**: String - **logger-name**: String -- **alter-function**: String ``("")`` +- **alter-function_name**: String ``("")`` +- **alter-function-code**: String ``("")`` +- **alter-function-file**: String ``("")`` .. _yaml-settings-DropResponseAction: @@ -116,7 +118,9 @@ Lua equivalent: :func:`LuaResponseAction` Parameters: -- **function**: String +- **function-name**: String ``("")`` +- **function-code**: String ``("")`` +- **function-file**: String ``("")`` .. _yaml-settings-LuaFFIResponseAction: @@ -130,7 +134,9 @@ Lua equivalent: :func:`LuaFFIResponseAction` Parameters: -- **function**: String +- **function-name**: String ``("")`` +- **function-code**: String ``("")`` +- **function-file**: String ``("")`` .. _yaml-settings-LuaFFIPerThreadResponseAction: @@ -159,7 +165,9 @@ Lua equivalent: :func:`RemoteLogResponseAction` Parameters: - **logger-name**: String -- **alter-function**: String ``("")`` +- **alter-function-name**: String ``("")`` +- **alter-function-code**: String ``("")`` +- **alter-function-file**: String ``("")`` - **server-id**: String ``("")`` - **ip-encrypt-key**: String ``("")`` - **include-cname**: Boolean ``(false)`` diff --git a/pdns/dnsdistdist/docs/reference/yaml-selectors.rst b/pdns/dnsdistdist/docs/reference/yaml-selectors.rst index 616f8af3bd..0952697311 100644 --- a/pdns/dnsdistdist/docs/reference/yaml-selectors.rst +++ b/pdns/dnsdistdist/docs/reference/yaml-selectors.rst @@ -193,7 +193,9 @@ Lua equivalent: :func:`LuaRule` Parameters: -- **function**: String +- **function-name**: String ``("")`` +- **function-code**: String ``("")`` +- **function-file**: String ``("")`` .. _yaml-settings-LuaFFISelector: @@ -207,7 +209,9 @@ Lua equivalent: :func:`LuaFFIRule` Parameters: -- **function**: String +- **function-name**: String ``("")`` +- **function-code**: String ``("")`` +- **function-file**: String ``("")`` .. _yaml-settings-LuaFFIPerThreadSelector: diff --git a/pdns/dnsdistdist/docs/reference/yaml-settings.rst b/pdns/dnsdistdist/docs/reference/yaml-settings.rst index 8da8a2424f..0a9e9609c4 100644 --- a/pdns/dnsdistdist/docs/reference/yaml-settings.rst +++ b/pdns/dnsdistdist/docs/reference/yaml-settings.rst @@ -165,7 +165,9 @@ CustomLoadBalancingPolicyConfiguration -------------------------------------- - **name**: String -- **function**: String +- **function-name**: String ``("")`` +- **function-code**: String ``("")`` +- **function-file**: String ``("")`` - **ffi**: Boolean ``(false)`` - **per-thread**: Boolean ``(false)`` @@ -213,7 +215,9 @@ DynamicRuleConfiguration - **warning-ratio**: Double ``(0.0)`` - **tag-name**: String ``("")`` - **tag-value**: String ``(0)`` -- **visitor-function**: String ``("")`` +- **visitor-function-name**: String ``("")`` +- **visitor-function-code**: String ``("")`` +- **visitor-function-file**: String ``("")`` - **rcode**: String ``("")`` - **qtype**: String ``("")`` - **minimum-number-of-responses**: Unsigned integer ``(0)`` @@ -302,6 +306,8 @@ HealthCheckConfiguration - **qclass**: String ``(IN)`` - **qtype**: String ``(A)`` - **function**: String ``("")`` +- **lua**: String ``("")`` +- **lua-file**: String ``("")`` - **timeout**: Unsigned integer ``(1000)`` - **set-cd**: Boolean ``(false)`` - **max-failures**: Unsigned integer ``(1)`` @@ -673,7 +679,9 @@ QueryCountConfiguration ----------------------- - **enabled**: Boolean ``(false)`` -- **filter**: String ``("")`` +- **filter-function-name**: String ``("")`` +- **filter-function-code**: String ``("")`` +- **filter-function-file**: String ``("")`` .. _yaml-settings-QueryRuleConfiguration: diff --git a/regression-tests.dnsdist/test_DNSCrypt.py b/regression-tests.dnsdist/test_DNSCrypt.py index 0d8daaff0c..6c6061fa06 100644 --- a/regression-tests.dnsdist/test_DNSCrypt.py +++ b/regression-tests.dnsdist/test_DNSCrypt.py @@ -304,13 +304,13 @@ query-rules: qname: "udp.protocols.dnscrypt.tests.powerdns.com." action: type: "Lua" - function: "checkDNSCryptUDP" + function-name: "checkDNSCryptUDP" - selector: type: "QName" qname: "tcp.protocols.dnscrypt.tests.powerdns.com." action: type: "Lua" - function: "checkDNSCryptTCP" + function-name: "checkDNSCryptTCP" """ _config_params = [] _yaml_config_params = ['_consoleKeyB64', '_consolePort', '_dnsDistPortDNSCrypt', '_providerName', '_testServerPort'] diff --git a/regression-tests.dnsdist/test_DOH.py b/regression-tests.dnsdist/test_DOH.py index 5e73a10d30..359258d491 100644 --- a/regression-tests.dnsdist/test_DOH.py +++ b/regression-tests.dnsdist/test_DOH.py @@ -880,7 +880,7 @@ query-rules: qname: "http-lua.doh.tests.powerdns.com." action: type: "Lua" - function: "dohHandler" + function-name: "dohHandler" """ _yaml_config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary'] _config_template = """ diff --git a/regression-tests.dnsdist/test_Yaml.py b/regression-tests.dnsdist/test_Yaml.py index d13e6c5371..eb56e672c7 100644 --- a/regression-tests.dnsdist/test_Yaml.py +++ b/regression-tests.dnsdist/test_Yaml.py @@ -41,6 +41,7 @@ backends: protocol: Do53 pools: - "tcp-pool" + - "inline" pools: - name: "tcp-pool" @@ -52,6 +53,15 @@ selectors: tcp: true query-rules: + - name: "route inline-yaml to inline pool" + selector: + type: "QNameSet" + qnames: + - "inline-lua.yaml.test.powerdns.com." + action: + type: "Pool" + pool-name: "inline" + stop-processing: true - name: "my-rule" selector: type: "And" @@ -64,6 +74,43 @@ query-rules: action: type: "Pool" pool-name: "tcp-pool" + +response-rules: + - name: "inline RD=0 TCP gets cleared" + selector: + type: "And" + selectors: + - type: "ByName" + selector-name: "is-tcp" + - type: "QNameSet" + qnames: + - "inline-lua.yaml.test.powerdns.com." + - type: "Lua" + name: "Match responses on RD=0 (inline)" + function-code: | + return function(dr) + local rd = dr.dh:getRD() + if not rd then + return true + end + return false + end + action: + type: "ClearRecordTypes" + types: + - 1 + - name: "inline RD=0 UDP gets truncated" + selector: + type: "And" + selectors: + - type: "QNameSet" + qnames: + - "inline-lua.yaml.test.powerdns.com." + - type: "Lua" + name: "Match responses on RD=0 (file)" + function-file: "yaml-config-files/yaml-inline-lua-file.yml" + action: + type: "TC" """ _webServerPort = pickAvailablePort() _dnsDistPort = pickAvailablePort() @@ -97,3 +144,53 @@ query-rules: receivedQuery.id = query.id self.assertEqual(receivedQuery, query) self.assertEqual(receivedResponse, response) + + def testInlineLua(self): + """ + Yaml: Inline Lua + """ + name = 'inline-lua.yaml.test.powerdns.com.' + + query = dns.message.make_query(name, 'A', 'IN') + query.flags &= ~dns.flags.RD + response = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, + 60, + dns.rdataclass.IN, + dns.rdatatype.A, + '127.0.0.1') + + response.answer.append(rrset) + truncatedResponse = dns.message.make_response(query) + truncatedResponse.flags |= dns.flags.TC + clearedResponse = dns.message.make_response(query) + + # UDP response without RD should be truncated + (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response=response) + receivedQuery.id = query.id + self.assertEqual(receivedQuery, query) + self.assertEqual(receivedResponse, truncatedResponse) + + # TCP response should have its A records cleared + (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response=response) + receivedQuery.id = query.id + self.assertEqual(receivedQuery, query) + self.assertEqual(receivedResponse, clearedResponse) + + # response with RD should be forwarded + query = dns.message.make_query(name, 'A', 'IN') + query.flags |= dns.flags.RD + response = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, + 60, + dns.rdataclass.IN, + dns.rdatatype.A, + '127.0.0.1') + + response.answer.append(rrset) + for method in ["sendUDPQuery", "sendTCPQuery"]: + sender = getattr(self, method) + (receivedQuery, receivedResponse) = sender(query, response=response) + receivedQuery.id = query.id + self.assertEqual(receivedQuery, query) + self.assertEqual(receivedResponse, response) diff --git a/regression-tests.dnsdist/yaml-config-files/yaml-inline-lua-file.yml b/regression-tests.dnsdist/yaml-config-files/yaml-inline-lua-file.yml new file mode 100644 index 0000000000..4d6b877cee --- /dev/null +++ b/regression-tests.dnsdist/yaml-config-files/yaml-inline-lua-file.yml @@ -0,0 +1,7 @@ +return function(dr) + local rd = dr.dh:getRD() + if not rd then + return true + end + return false +end