]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Support inline and "detached to a file" Lua code in YAML
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 7 Jan 2025 15:28:45 +0000 (16:28 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 16 Jan 2025 08:51:11 +0000 (09:51 +0100)
34 files changed:
pdns/dnsdistdist/dnsdist-actions-definitions.yml
pdns/dnsdistdist/dnsdist-actions-factory-generated.cc
pdns/dnsdistdist/dnsdist-actions-factory-generated.hh
pdns/dnsdistdist/dnsdist-actions-factory.cc
pdns/dnsdistdist/dnsdist-actions-factory.hh
pdns/dnsdistdist/dnsdist-configuration-yaml.cc
pdns/dnsdistdist/dnsdist-lua-actions-generated.cc
pdns/dnsdistdist/dnsdist-lua-actions.cc
pdns/dnsdistdist/dnsdist-lua-response-actions-generated.cc
pdns/dnsdistdist/dnsdist-lua-rules.cc
pdns/dnsdistdist/dnsdist-lua-selectors-generated.cc
pdns/dnsdistdist/dnsdist-lua.hh
pdns/dnsdistdist/dnsdist-response-actions-definitions.yml
pdns/dnsdistdist/dnsdist-response-actions-factory-generated.cc
pdns/dnsdistdist/dnsdist-response-actions-factory-generated.hh
pdns/dnsdistdist/dnsdist-rules-factory.hh
pdns/dnsdistdist/dnsdist-rules-generator.py
pdns/dnsdistdist/dnsdist-rules.cc
pdns/dnsdistdist/dnsdist-rust-bridge-actions-generated.cc
pdns/dnsdistdist/dnsdist-rust-bridge-selectors-generated.cc
pdns/dnsdistdist/dnsdist-rust-lib/dnsdist-settings-generator.py
pdns/dnsdistdist/dnsdist-rust-lib/rust/src/lib.rs
pdns/dnsdistdist/dnsdist-selectors-definitions.yml
pdns/dnsdistdist/dnsdist-selectors-factory-generated.cc
pdns/dnsdistdist/dnsdist-selectors-factory-generated.hh
pdns/dnsdistdist/dnsdist-settings-definitions.yml
pdns/dnsdistdist/docs/reference/yaml-actions.rst
pdns/dnsdistdist/docs/reference/yaml-response-actions.rst
pdns/dnsdistdist/docs/reference/yaml-selectors.rst
pdns/dnsdistdist/docs/reference/yaml-settings.rst
regression-tests.dnsdist/test_DNSCrypt.py
regression-tests.dnsdist/test_DOH.py
regression-tests.dnsdist/test_Yaml.py
regression-tests.dnsdist/yaml-config-files/yaml-inline-lua-file.yml [new file with mode: 0644]

index dd0bd648bc635f2d0902ae5bcbaaee3b3eeb6225..ea8ab18f779066eafbe7576986d9cb10764bd93c 100644 (file)
       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"
index 7c1f5a485560e4763e9bc8ed9706ed399bc2c7fd..467412d4c8754d40acd03774cb4b7c223b11e9c6 100644 (file)
@@ -19,14 +19,6 @@ std::shared_ptr<DNSAction> getLogAction(const std::string& fileName, bool binary
 {
   return std::shared_ptr<DNSAction>(new LogAction(fileName, binary, append, buffered, verboseOnly, includeTimestamp));
 }
-std::shared_ptr<DNSAction> getLuaAction(dnsdist::actions::LuaActionFunction function)
-{
-  return std::shared_ptr<DNSAction>(new LuaAction(function));
-}
-std::shared_ptr<DNSAction> getLuaFFIAction(dnsdist::actions::LuaActionFFIFunction function)
-{
-  return std::shared_ptr<DNSAction>(new LuaFFIAction(function));
-}
 std::shared_ptr<DNSAction> getLuaFFIPerThreadAction(const std::string& code)
 {
   return std::shared_ptr<DNSAction>(new LuaFFIPerThreadAction(code));
index fb18c7b78dcffc53b53710126746e5ce24f5d5f0..772040b10056bead3cd1f2aa664eeb4f4dbf37cf 100644 (file)
@@ -4,8 +4,6 @@ std::shared_ptr<DNSAction> getDelayAction(uint32_t msec);
 std::shared_ptr<DNSAction> getDropAction();
 std::shared_ptr<DNSAction> getSetEDNSOptionAction(uint32_t code, const std::string& data);
 std::shared_ptr<DNSAction> getLogAction(const std::string& fileName, bool binary, bool append, bool buffered, bool verboseOnly, bool includeTimestamp);
-std::shared_ptr<DNSAction> getLuaAction(dnsdist::actions::LuaActionFunction function);
-std::shared_ptr<DNSAction> getLuaFFIAction(dnsdist::actions::LuaActionFFIFunction function);
 std::shared_ptr<DNSAction> getLuaFFIPerThreadAction(const std::string& code);
 std::shared_ptr<DNSAction> getNoneAction();
 std::shared_ptr<DNSAction> getPoolAction(const std::string& poolName, bool stopProcessing);
index 052d08f7c3264d2965add3ecc72cf86ff8f21dfd..5a0b7c997422d2ba9a08be3ba6c18709bffbc327 100644 (file)
@@ -2302,6 +2302,26 @@ private:
   uint32_t d_max{std::numeric_limits<uint32_t>::max()};
 };
 
+std::shared_ptr<DNSAction> getLuaAction(dnsdist::actions::LuaActionFunction function)
+{
+  return std::shared_ptr<DNSAction>(new LuaAction(function));
+}
+
+std::shared_ptr<DNSAction> getLuaFFIAction(dnsdist::actions::LuaActionFFIFunction function)
+{
+  return std::shared_ptr<DNSAction>(new LuaFFIAction(function));
+}
+
+std::shared_ptr<DNSResponseAction> getLuaResponseAction(dnsdist::actions::LuaResponseActionFunction function)
+{
+  return std::shared_ptr<DNSResponseAction>(new LuaResponseAction(function));
+}
+
+std::shared_ptr<DNSResponseAction> getLuaFFIResponseAction(dnsdist::actions::LuaResponseActionFFIFunction function)
+{
+  return std::shared_ptr<DNSResponseAction>(new LuaFFIResponseAction(function));
+}
+
 #ifndef DISABLE_PROTOBUF
 std::shared_ptr<DNSAction> getRemoteLogAction(RemoteLogActionConfiguration& config)
 {
index 4d2cd4537741ea43bd6d3b7e2eeed2f0c965154f..8aa98eee1338efdd9c92b143922744899419f362 100644 (file)
@@ -62,6 +62,11 @@ struct SOAParams
 #include "dnsdist-actions-factory-generated.hh"
 #include "dnsdist-response-actions-factory-generated.hh"
 
+std::shared_ptr<DNSAction> getLuaAction(dnsdist::actions::LuaActionFunction function);
+std::shared_ptr<DNSAction> getLuaFFIAction(dnsdist::actions::LuaActionFFIFunction function);
+std::shared_ptr<DNSResponseAction> getLuaResponseAction(dnsdist::actions::LuaResponseActionFunction function);
+std::shared_ptr<DNSResponseAction> getLuaFFIResponseAction(dnsdist::actions::LuaResponseActionFFIFunction function);
+
 std::shared_ptr<DNSAction> getContinueAction(std::shared_ptr<DNSAction> action);
 #ifdef HAVE_DNS_OVER_HTTPS
 std::shared_ptr<DNSAction> getHTTPStatusAction(uint16_t status, PacketBuffer&& body, const std::string& contentType, const dnsdist::ResponseConfig& responseConfig);
index b2185c3f15cc7facda46d2c8e29ec54fc94c53c2..a40c21bbe390b10fe52cd5a94993a746aff38ad2 100644 (file)
@@ -115,6 +115,57 @@ static T checkedConversionFromStr(const std::string& context, const std::string&
   return checkedConversionFromStr<T>(context, parameterName, std::string(str));
 }
 
+template <class T>
+static bool getOptionalLuaFunction(T& destination, const ::rust::string& functionName)
+{
+  auto lua = g_lua.lock();
+  auto function = lua->readVariable<boost::optional<T>>(std::string(functionName));
+  if (!function) {
+    return false;
+  }
+  destination = *function;
+  return true;
+}
+
+static std::optional<std::string> 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<char>(file), {});
+}
+
+template <class FuncType>
+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<FuncType>(destination, functionName);
+  }
+  if (!functionCode.empty()) {
+    auto function = dnsdist::lua::getFunctionFromLuaCode<FuncType>(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<FuncType>(*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<int> getCPUPiningFromStr(const std::string& context, const std::string& cpuStr)
 {
   std::set<int> cpus;
@@ -301,18 +352,6 @@ static bool handleTLSConfiguration(const dnsdist::rust::settings::BindConfigurat
   return true;
 }
 
-template <class T>
-static bool getOptionalLuaFunction(T& destination, const ::rust::string& functionName)
-{
-  auto lua = g_lua.lock();
-  auto function = lua->readVariable<boost::optional<T>>(std::string(functionName));
-  if (!function) {
-    return false;
-  }
-  destination = *function;
-  return true;
-}
-
 static std::shared_ptr<DownstreamState> createBackendFromConfiguration(const dnsdist::rust::settings::BackendConfiguration& config, bool configCheck)
 {
   DownstreamState::Config backendConfig;
@@ -359,7 +398,7 @@ static std::shared_ptr<DownstreamState> createBackendFromConfiguration(const dns
   backendConfig.maxCheckFailures = hcConf.max_failures;
   backendConfig.minRiseSuccesses = hcConf.rise;
 
-  getOptionalLuaFunction<DownstreamState::checkfunc_t>(backendConfig.checkFunction, hcConf.function);
+  getLuaFunctionFromConfiguration<DownstreamState::checkfunc_t>(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<DynBlockRulesGroup::smtVisitor_t>(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<dnsdist_ffi_stat_node_visitor_t>(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<char>(file), std::istreambuf_iterator<char>());
-
-    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<dnsdist::QueryCount::Configuration::Filter>(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<ServerPolicy>(std::string(policy.name), std::string(policy.function));
+          auto policyObj = std::make_shared<ServerPolicy>(std::string(policy.name), std::string(policy.function_code));
           registerType<ServerPolicy>(policyObj, policy.name);
         }
         else {
           ServerPolicy::ffipolicyfunc_t function;
 
-          if (!getOptionalLuaFunction<ServerPolicy::ffipolicyfunc_t>(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<ServerPolicy>(std::string(policy.name), std::move(function));
           registerType<ServerPolicy>(policyObj, policy.name);
@@ -954,8 +988,8 @@ bool loadConfigurationFromFile(const std::string& fileName, bool isClient, bool
       }
       else {
         ServerPolicy::policyfunc_t function;
-        if (!getOptionalLuaFunction<ServerPolicy::policyfunc_t>(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<ServerPolicy>(std::string(policy.name), std::move(function), true);
         registerType<ServerPolicy>(policyObj, policy.name);
@@ -1091,14 +1125,24 @@ static std::vector<::SVCRecordParameters> convertSVCRecordParameters(const ::rus
   return cppParameters;
 }
 
-template <class T>
-T convertLuaFunction(const ::rust::String& context, const ::rust::String& name)
+std::shared_ptr<DNSActionWrapper> getLuaAction(const LuaActionConfiguration& config)
 {
-  T function;
-  if (!dnsdist::configuration::yaml::getOptionalLuaFunction<T>(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<DNSActionWrapper> 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<DNSActionWrapper> getContinueAction(const ContinueActionConfiguration& config)
@@ -1159,6 +1203,26 @@ std::shared_ptr<DNSActionWrapper> getSpoofRawAction(const SpoofRawActionConfigur
   return newDNSActionWrapper(std::move(action), config.name);
 }
 
+std::shared_ptr<DNSResponseActionWrapper> 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<DNSResponseActionWrapper> 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<DNSResponseActionWrapper> getClearRecordTypesResponseAction(const ClearRecordTypesResponseActionConfiguration& config)
 {
   std::unordered_set<QType> qtypes{};
@@ -1297,7 +1361,7 @@ std::shared_ptr<DNSActionWrapper> 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<dnsdist::actions::DnstapAlterFunction>(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<DNSResponseActionWrapper> 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<dnsdist::actions::DnstapAlterResponseFunction>(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<DNSActionWrapper> getRemoteLogAction(const RemoteLogActionConfig
     }
   }
   dnsdist::actions::ProtobufAlterFunction alterFunc;
-  if (dnsdist::configuration::yaml::getOptionalLuaFunction<dnsdist::actions::ProtobufAlterFunction>(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<DNSResponseActionWrapper> getRemoteLogResponseAction(const Remot
     actionConfig.exportExtendedErrorsToMeta = std::string(config.export_extended_errors_to_meta);
   }
   dnsdist::actions::ProtobufAlterResponseFunction alterFunc;
-  if (dnsdist::configuration::yaml::getOptionalLuaFunction<dnsdist::actions::ProtobufAlterResponseFunction>(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<DNSSelector> 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<DNSSelector> 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<DNSSelector> getAndSelector(const AndSelectorConfiguration& config)
 {
   std::vector<std::shared_ptr<DNSRule>> selectors;
index 512391972cc419a08340e199722e1b433d7d4d7d..2a4f1434408e1e8aed53bf501c444edec479235e 100644 (file)
@@ -14,12 +14,6 @@ luaCtx.writeFunction("SetEDNSOptionAction", [](uint32_t code, std::string data)
 luaCtx.writeFunction("LogAction", [](boost::optional<std::string> fileName, boost::optional<bool> binary, boost::optional<bool> append, boost::optional<bool> buffered, boost::optional<bool> verboseOnly, boost::optional<bool> 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);
 });
index f35246ceba7f135184524d77710a788bab5954a3..5015bed0731458a125361a897ca6b26d03aba881 100644 (file)
@@ -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<std::string> inp, boost::optional<responseParams_t> vars) {
     vector<ComboAddress> addrs;
     if (auto* ipaddr = boost::get<std::string>(&inp)) {
index bc5a13ba7c84fe4b9b4be1cdf5e9be9cec93dc80..b6cfa242b6f44a27e273c8ca55ff4f68a8038831 100644 (file)
@@ -11,12 +11,6 @@ luaCtx.writeFunction("DropResponseAction", []() {
 luaCtx.writeFunction("LogResponseAction", [](boost::optional<std::string> fileName, boost::optional<bool> append, boost::optional<bool> buffered, boost::optional<bool> verboseOnly, boost::optional<bool> 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);
 });
index 8709a2eb15f4b18628d2d07c3a67c23c13664ec4..52468bce21d02560e5b8b0ab4a4f27bc32e3ca31 100644 (file)
@@ -576,6 +576,14 @@ void setupLuaRules(LuaContext& luaCtx)
     return std::shared_ptr<DNSRule>(new NotRule(rule));
   });
 
+  luaCtx.writeFunction("LuaRule", [](dnsdist::selectors::LuaSelectorFunction function) {
+    return std::shared_ptr<DNSRule>(dnsdist::selectors::getLuaSelector(function));
+  });
+
+  luaCtx.writeFunction("LuaFFIRule", [](dnsdist::selectors::LuaSelectorFFIFunction function) {
+    return std::shared_ptr<DNSRule>(dnsdist::selectors::getLuaFFISelector(function));
+  });
+
   luaCtx.writeFunction("RCodeRule", [](uint64_t rcode) {
     checkParameterBound("RCodeRule", rcode, std::numeric_limits<uint8_t>::max());
     return std::shared_ptr<DNSRule>(new RCodeRule(rcode));
index d16d9050d45a901432262bd43ff483487447ee21..bb870cfdd7cbd99c33074c0f27cd19f9bbae96d3 100644 (file)
@@ -26,12 +26,6 @@ luaCtx.writeFunction("HTTPPathRule", [](std::string path) {
 luaCtx.writeFunction("HTTPPathRegexRule", [](std::string expression) {
   return std::shared_ptr<DNSRule>(dnsdist::selectors::getHTTPPathRegexSelector(expression));
 });
-luaCtx.writeFunction("LuaRule", [](dnsdist::selectors::LuaSelectorFunction function) {
-  return std::shared_ptr<DNSRule>(dnsdist::selectors::getLuaSelector(function));
-});
-luaCtx.writeFunction("LuaFFIRule", [](dnsdist::selectors::LuaSelectorFFIFunction function) {
-  return std::shared_ptr<DNSRule>(dnsdist::selectors::getLuaFFISelector(function));
-});
 luaCtx.writeFunction("LuaFFIPerThreadRule", [](std::string code) {
   return std::shared_ptr<DNSRule>(dnsdist::selectors::getLuaFFIPerThreadSelector(code));
 });
index b6e44b98095a7c0a1753611c29a3805015ace2a0..09d18a643b005cba97376ff0fd94dfc69fcf55df 100644 (file)
@@ -66,6 +66,23 @@ namespace dnsdist::lua
 {
 void setupLua(LuaContext& luaCtx, bool client, bool configCheck);
 void setupConfigurationItems(LuaContext& luaCtx);
+
+template <class FunctionType>
+std::optional<FunctionType> getFunctionFromLuaCode(const std::string& code, const std::string& context)
+{
+  try {
+    auto function = g_lua.lock()->executeCode<FunctionType>(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
index a7553ce91728611619417f1c8bf0141aa9a4237c..45a2d420c653e542999b78f8af5171b59c9bf82c 100644 (file)
       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"
index 3066ffb12da4b6fd31f187418b25349520fd6863..b02eb932bcabd43d2fe3db19970b6049dceec451 100644 (file)
@@ -15,14 +15,6 @@ std::shared_ptr<DNSResponseAction> getLogResponseAction(const std::string& fileN
 {
   return std::shared_ptr<DNSResponseAction>(new LogResponseAction(fileName, append, buffered, verboseOnly, includeTimestamp));
 }
-std::shared_ptr<DNSResponseAction> getLuaResponseAction(dnsdist::actions::LuaResponseActionFunction function)
-{
-  return std::shared_ptr<DNSResponseAction>(new LuaResponseAction(function));
-}
-std::shared_ptr<DNSResponseAction> getLuaFFIResponseAction(dnsdist::actions::LuaResponseActionFFIFunction function)
-{
-  return std::shared_ptr<DNSResponseAction>(new LuaFFIResponseAction(function));
-}
 std::shared_ptr<DNSResponseAction> getLuaFFIPerThreadResponseAction(const std::string& code)
 {
   return std::shared_ptr<DNSResponseAction>(new LuaFFIPerThreadResponseAction(code));
index 839dbaf86b03b6e3088e40e39fcba8884d88b90c..5858bf61c632580dc922003ef025edfc20ca5f13 100644 (file)
@@ -3,8 +3,6 @@ std::shared_ptr<DNSResponseAction> getAllowResponseAction();
 std::shared_ptr<DNSResponseAction> getDelayResponseAction(uint32_t msec);
 std::shared_ptr<DNSResponseAction> getDropResponseAction();
 std::shared_ptr<DNSResponseAction> getLogResponseAction(const std::string& fileName, bool append, bool buffered, bool verboseOnly, bool includeTimestamp);
-std::shared_ptr<DNSResponseAction> getLuaResponseAction(dnsdist::actions::LuaResponseActionFunction function);
-std::shared_ptr<DNSResponseAction> getLuaFFIResponseAction(dnsdist::actions::LuaResponseActionFFIFunction function);
 std::shared_ptr<DNSResponseAction> getLuaFFIPerThreadResponseAction(const std::string& code);
 std::shared_ptr<DNSResponseAction> getSetExtendedDNSErrorResponseAction(uint16_t infoCode, const std::string& extraText);
 std::shared_ptr<DNSResponseAction> getSetReducedTTLResponseAction(uint8_t percentage);
index 08711f6fe89e066a0dacc946791a8a3028c555d9..ccec8356b6fe8a3b8de018fc9c34467b45a89ed8 100644 (file)
@@ -1499,6 +1499,8 @@ namespace dnsdist::selectors
 std::shared_ptr<AndRule> getAndSelector(const std::vector<std::shared_ptr<DNSRule>>& rules);
 std::shared_ptr<OrRule> getOrSelector(const std::vector<std::shared_ptr<DNSRule>>& rules);
 std::shared_ptr<NotRule> getNotSelector(const std::shared_ptr<DNSRule>& rule);
+std::shared_ptr<LuaRule> getLuaSelector(const dnsdist::selectors::LuaSelectorFunction& func);
+std::shared_ptr<LuaFFIRule> getLuaFFISelector(const dnsdist::selectors::LuaSelectorFFIFunction& func);
 std::shared_ptr<QNameRule> getQNameSelector(const DNSName& qname);
 std::shared_ptr<QNameSetRule> getQNameSetSelector(const DNSNameSet& qnames);
 std::shared_ptr<SuffixMatchNodeRule> getQNameSuffixSelector(const SuffixMatchNode& suffixes, bool quiet);
index cb6c0d73f840b1c465b6f42eb41f49f47aaedba6..7a92c0f983647703e5fad3de10d38672ad3c1042 100644 (file)
@@ -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
index e4904fdca1927c20a1286e0ddc1f78398288cb00..5b97eba9d2f1c8ed1be2d5e61dc4212b7e505ee2 100644 (file)
@@ -191,6 +191,16 @@ std::shared_ptr<NotRule> getNotSelector(const std::shared_ptr<DNSRule>& rule)
   return std::make_shared<NotRule>(rule);
 }
 
+std::shared_ptr<LuaRule> getLuaSelector(const dnsdist::selectors::LuaSelectorFunction& func)
+{
+  return std::make_shared<LuaRule>(func);
+}
+
+std::shared_ptr<LuaFFIRule> getLuaFFISelector(const dnsdist::selectors::LuaSelectorFFIFunction& func)
+{
+  return std::make_shared<LuaFFIRule>(func);
+}
+
 // NOLINTNEXTLINE(bugprone-suspicious-include)
 #include "dnsdist-selectors-factory-generated.cc"
 
index 3204c13232bc1ecdd22e103cbd0ea966b2002def..6bce7dab5ad03b3a7d9ab858ae0d4b74bf77c7b5 100644 (file)
@@ -34,16 +34,6 @@ std::shared_ptr<DNSActionWrapper> 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<DNSActionWrapper> getLuaAction(const LuaActionConfiguration& config)
-{
-  auto action = dnsdist::actions::getLuaAction(convertLuaFunction<dnsdist::actions::LuaActionFunction>("LuaActionConfiguration", config.function));
-  return newDNSActionWrapper(std::move(action), config.name);
-}
-std::shared_ptr<DNSActionWrapper> getLuaFFIAction(const LuaFFIActionConfiguration& config)
-{
-  auto action = dnsdist::actions::getLuaFFIAction(convertLuaFunction<dnsdist::actions::LuaActionFFIFunction>("LuaFFIActionConfiguration", config.function));
-  return newDNSActionWrapper(std::move(action), config.name);
-}
 std::shared_ptr<DNSActionWrapper> getLuaFFIPerThreadAction(const LuaFFIPerThreadActionConfiguration& config)
 {
   auto action = dnsdist::actions::getLuaFFIPerThreadAction(std::string(config.code));
@@ -184,16 +174,6 @@ std::shared_ptr<DNSResponseActionWrapper> 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<DNSResponseActionWrapper> getLuaResponseAction(const LuaResponseActionConfiguration& config)
-{
-  auto action = dnsdist::actions::getLuaResponseAction(convertLuaFunction<dnsdist::actions::LuaResponseActionFunction>("LuaResponseActionConfiguration", config.function));
-  return newDNSResponseActionWrapper(std::move(action), config.name);
-}
-std::shared_ptr<DNSResponseActionWrapper> getLuaFFIResponseAction(const LuaFFIResponseActionConfiguration& config)
-{
-  auto action = dnsdist::actions::getLuaFFIResponseAction(convertLuaFunction<dnsdist::actions::LuaResponseActionFFIFunction>("LuaFFIResponseActionConfiguration", config.function));
-  return newDNSResponseActionWrapper(std::move(action), config.name);
-}
 std::shared_ptr<DNSResponseActionWrapper> getLuaFFIPerThreadResponseAction(const LuaFFIPerThreadResponseActionConfiguration& config)
 {
   auto action = dnsdist::actions::getLuaFFIPerThreadResponseAction(std::string(config.code));
index 8ae735d51b6715e62c727a4927ccda6b2181daa2..fad3bc99521716184f0430bdd3426b1a4e07a658 100644 (file)
@@ -44,16 +44,6 @@ std::shared_ptr<DNSSelector> getHTTPPathRegexSelector(const HTTPPathRegexSelecto
   auto selector = dnsdist::selectors::getHTTPPathRegexSelector(std::string(config.expression));
   return newDNSSelector(std::move(selector), config.name);
 }
-std::shared_ptr<DNSSelector> getLuaSelector(const LuaSelectorConfiguration& config)
-{
-  auto selector = dnsdist::selectors::getLuaSelector(convertLuaFunction<dnsdist::selectors::LuaSelectorFunction>("LuaSelectorConfiguration", config.function));
-  return newDNSSelector(std::move(selector), config.name);
-}
-std::shared_ptr<DNSSelector> getLuaFFISelector(const LuaFFISelectorConfiguration& config)
-{
-  auto selector = dnsdist::selectors::getLuaFFISelector(convertLuaFunction<dnsdist::selectors::LuaSelectorFFIFunction>("LuaFFISelectorConfiguration", config.function));
-  return newDNSSelector(std::move(selector), config.name);
-}
 std::shared_ptr<DNSSelector> getLuaFFIPerThreadSelector(const LuaFFIPerThreadSelectorConfiguration& config)
 {
   auto selector = dnsdist::selectors::getLuaFFIPerThreadSelector(std::string(config.code));
index f9a7fe8a5f0477266efc0756624e15f4d967978e..b9d4a78135701bc2ad1269c1f3ad7c3b24e91a04 100644 (file)
@@ -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
 
index f975c906a6aea8926833e4c3e5db2e4a2080409d..6353236c8ce845a27dbfb3d763ef0efc86ab727c 100644 (file)
@@ -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")]
index 7f6c9ede299f9233191a0d1b52f5467ffcd28fcf..182cbad8c81f41ce38b546bd3f40399128634119 100644 (file)
@@ -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.
 
index 224ff58f42dd1639243289d7794d342928fbfa2d..01894a8cab80a3ec524341a00333aa370320b14b 100644 (file)
@@ -35,14 +35,6 @@ std::shared_ptr<HTTPPathRegexRule> getHTTPPathRegexSelector(const std::string& e
 {
   return std::make_shared<HTTPPathRegexRule>(expression);
 }
-std::shared_ptr<LuaRule> getLuaSelector(dnsdist::selectors::LuaSelectorFunction function)
-{
-  return std::make_shared<LuaRule>(function);
-}
-std::shared_ptr<LuaFFIRule> getLuaFFISelector(dnsdist::selectors::LuaSelectorFFIFunction function)
-{
-  return std::make_shared<LuaFFIRule>(function);
-}
 std::shared_ptr<LuaFFIPerThreadRule> getLuaFFIPerThreadSelector(const std::string& code)
 {
   return std::make_shared<LuaFFIPerThreadRule>(code);
index fe48132d4756f98c343c4d4bda6d2f504663b045..bf4b579393dc8b070b3852de429301a0db68497d 100644 (file)
@@ -8,8 +8,6 @@ std::shared_ptr<ERCodeRule> getERCodeSelector(uint64_t rcode);
 std::shared_ptr<HTTPHeaderRule> getHTTPHeaderSelector(const std::string& header, const std::string& expression);
 std::shared_ptr<HTTPPathRule> getHTTPPathSelector(const std::string& path);
 std::shared_ptr<HTTPPathRegexRule> getHTTPPathRegexSelector(const std::string& expression);
-std::shared_ptr<LuaRule> getLuaSelector(dnsdist::selectors::LuaSelectorFunction function);
-std::shared_ptr<LuaFFIRule> getLuaFFISelector(dnsdist::selectors::LuaSelectorFFIFunction function);
 std::shared_ptr<LuaFFIPerThreadRule> getLuaFFIPerThreadSelector(const std::string& code);
 std::shared_ptr<MaxQPSRule> getMaxQPSSelector(uint32_t qps, std::optional<uint32_t> burst);
 std::shared_ptr<MaxQPSIPRule> getMaxQPSIPSelector(uint32_t qps, std::optional<uint8_t> ipv4Mask, std::optional<uint8_t> ipv6Mask, std::optional<uint32_t> burst, std::optional<uint32_t> expiration, std::optional<uint32_t> cleanupDelay, std::optional<uint32_t> scanFraction, std::optional<uint32_t> shards);
index 25910f860e3b6db1e173665e9b08162e68e31907..821ace3017d631e0274cde40a5501ca997a52f59 100644 (file)
@@ -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"
index 2b64625f710b6a261b90938f1205fb1d0445a252..30dd7d1acb0e5c9e1b514c37298e5ef41ccb5381 100644 (file)
@@ -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
index 34e2f884887988476977f25b36e316eb821d675c..db91181e26eab4c472df839b6a88d7deaf9290f4 100644 (file)
@@ -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)``
index 616f8af3bdd6dc3d81bbfa8de294c4465ff751d8..09526973119762c85780229653057c28b23275e7 100644 (file)
@@ -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:
index 8da8a2424f7fbb9cab2bef8f97fdb53bddeb12d7..0a9e9609c4766f813dd02ee976fa3fa035d21ee8 100644 (file)
@@ -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:
index 0d8daaff0c36b1d5595644ac80b6e2fbb3d32aa1..6c6061fa06981d0956d5e170e166e10819453154 100644 (file)
@@ -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']
index 5e73a10d30500abbc723bd1d31f656ddf17cd650..359258d4919ff13bf26588e25dcdf8f399367dc5 100644 (file)
@@ -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 = """
index d13e6c53712e95bc47c4f263ef615c08265a698f..eb56e672c72083c136ad5ea25c9029691dbaeba7 100644 (file)
@@ -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 (file)
index 0000000..4d6b877
--- /dev/null
@@ -0,0 +1,7 @@
+return function(dr)
+  local rd = dr.dh:getRD()
+  if not rd then
+    return true
+  end
+  return false
+end