]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Merge pull request #13013 from rgacogne/ddist-get-rule-action-matched
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 1 Aug 2023 11:23:01 +0000 (13:23 +0200)
committerGitHub <noreply@github.com>
Tue, 1 Aug 2023 11:23:01 +0000 (13:23 +0200)
dnsdist: Add Lua bindings to access selector and action

pdns/dnsdist-console.cc
pdns/dnsdist-lua-rules.cc
pdns/dnsdist.hh
pdns/dnsdistdist/docs/rules-actions.rst

index e3e5bcf3258c0be9c88a8b061624cf592b59e2d9..f2e381f222bdb075d054265a00d056b4dfcdb697 100644 (file)
@@ -519,6 +519,8 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "getAction", true, "n", "Returns the Action associated with rule n" },
   { "getBind", true, "n", "returns the listener at index n" },
   { "getBindCount", true, "", "returns the number of listeners all kinds" },
+  { "getCacheHitResponseRule", true, "selector", "Return the cache-hit response rule corresponding to the selector, if any" },
+  { "getCacheInsertedResponseRule", true, "selector", "Return the cache-inserted response rule corresponding to the selector, if any" },
   { "getCurrentTime", true, "", "returns the current time" },
   { "getDNSCryptBind", true, "n", "return the `DNSCryptContext` object corresponding to the bind `n`" },
   { "getDNSCryptBindCount", true, "", "returns the number of DNSCrypt listeners" },
@@ -535,7 +537,10 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "getPoolNames", true, "", "returns a table with all the pool names" },
   { "getQueryCounters", true, "[max=10]", "show current buffer of query counters, limited by 'max' if provided" },
   { "getResponseRing", true, "", "return the current content of the response ring" },
+  { "getResponseRule", true, "selector", "Return the response rule corresponding to the selector, if any" },
   { "getRespRing", true, "", "return the qname/rcode content of the response ring" },
+  { "getRule", true, "selector", "Return the rule corresponding to the selector, if any" },
+  { "getSelfAnsweredResponseRule", true, "selector", "Return the self-answered response rule corresponding to the selector, if any" },
   { "getServer", true, "id", "returns server with index 'n' or whose uuid matches if 'id' is an UUID string" },
   { "getServers", true, "", "returns a table with all defined servers" },
   { "getStatisticsCounters", true, "", "returns a map of statistic counters" },
index 8549014e72efef989069fb4d6e9289bce5b84954..2495b4a9ee8e2cd259dfd9ce3a21d986abc9ef3a 100644 (file)
@@ -224,12 +224,67 @@ static std::vector<T> getTopRules(const std::vector<T>& rules, unsigned int top)
   return results;
 }
 
+template<typename T>
+static LuaArray<T> toLuaArray(std::vector<T>&& rules)
+{
+  LuaArray<T> results;
+  results.reserve(rules.size());
+
+  size_t pos = 1;
+  for (auto& rule : rules) {
+    results.emplace_back(pos, std::move(rule));
+    pos++;
+  }
+
+  return results;
+}
+
+template <typename T>
+static boost::optional<T> getRuleFromSelector(const std::vector<T>& rules, const boost::variant<int, std::string>& selector)
+{
+  if (auto str = boost::get<std::string>(&selector)) {
+    /* let's see if this a UUID */
+    try {
+      const auto uuid = getUniqueID(*str);
+      for (const auto& rule : rules) {
+        if (rule.d_id == uuid) {
+          return rule;
+        }
+      }
+    }
+    catch (const std::exception& e) {
+      /* a name, then */
+      for (const auto& rule : rules) {
+        if (rule.d_name == *str) {
+          return rule;
+        }
+      }
+    }
+  }
+  else if (auto pos = boost::get<int>(&selector)) {
+    /* this will throw a std::out_of_range exception if the
+       supplied position is out of bounds, this is fine */
+    return rules.at(*pos);
+  }
+  return boost::none;
+}
+
 void setupLuaRules(LuaContext& luaCtx)
 {
   luaCtx.writeFunction("makeRule", makeRule);
 
   luaCtx.registerFunction<string(std::shared_ptr<DNSRule>::*)()const>("toString", [](const std::shared_ptr<DNSRule>& rule) { return rule->toString(); });
 
+  luaCtx.registerFunction<uint64_t(std::shared_ptr<DNSRule>::*)()const>("getMatches", [](const std::shared_ptr<DNSRule>& rule) { return rule->d_matches.load(); });
+
+  luaCtx.registerFunction<std::shared_ptr<DNSRule>(DNSDistRuleAction::*)()const>("getSelector", [](const DNSDistRuleAction& rule) { return rule.d_rule; });
+
+  luaCtx.registerFunction<std::shared_ptr<DNSAction>(DNSDistRuleAction::*)()const>("getAction", [](const DNSDistRuleAction& rule) { return rule.d_action; });
+
+  luaCtx.registerFunction<std::shared_ptr<DNSRule>(DNSDistResponseRuleAction::*)()const>("getSelector", [](const DNSDistResponseRuleAction& rule) { return rule.d_rule; });
+
+  luaCtx.registerFunction<std::shared_ptr<DNSResponseAction>(DNSDistResponseRuleAction::*)()const>("getAction", [](const DNSDistResponseRuleAction& rule) { return rule.d_action; });
+
   luaCtx.writeFunction("showResponseRules", [](boost::optional<ruleparams_t> vars) {
       showRules(&g_respruleactions, vars);
     });
@@ -327,10 +382,15 @@ void setupLuaRules(LuaContext& luaCtx)
         });
     });
 
+  luaCtx.writeFunction("getRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistRuleAction> {
+    auto rules = g_ruleactions.getLocal();
+    return getRuleFromSelector(*rules, selector);
+  });
+
   luaCtx.writeFunction("getTopRules", [](boost::optional<unsigned int> top) {
     setLuaNoSideEffect();
     auto rules = g_ruleactions.getLocal();
-    return getTopRules(*rules, (top ? *top : 10));
+    return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
   });
 
   luaCtx.writeFunction("topRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
@@ -339,10 +399,15 @@ void setupLuaRules(LuaContext& luaCtx)
     return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars);
   });
 
+  luaCtx.writeFunction("getCacheHitResponseRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistResponseRuleAction> {
+    auto rules = g_cachehitrespruleactions.getLocal();
+    return getRuleFromSelector(*rules, selector);
+  });
+
   luaCtx.writeFunction("getTopCacheHitResponseRules", [](boost::optional<unsigned int> top) {
     setLuaNoSideEffect();
     auto rules = g_cachehitrespruleactions.getLocal();
-    return getTopRules(*rules, (top ? *top : 10));
+    return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
   });
 
   luaCtx.writeFunction("topCacheHitResponseRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
@@ -351,10 +416,15 @@ void setupLuaRules(LuaContext& luaCtx)
     return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars);
   });
 
+  luaCtx.writeFunction("getCacheInsertedResponseRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistResponseRuleAction> {
+    auto rules = g_cacheInsertedRespRuleActions.getLocal();
+    return getRuleFromSelector(*rules, selector);
+  });
+
   luaCtx.writeFunction("getTopCacheInsertedResponseRules", [](boost::optional<unsigned int> top) {
     setLuaNoSideEffect();
     auto rules = g_cacheInsertedRespRuleActions.getLocal();
-    return getTopRules(*rules, (top ? *top : 10));
+    return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
   });
 
   luaCtx.writeFunction("topCacheInsertedResponseRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
@@ -363,10 +433,15 @@ void setupLuaRules(LuaContext& luaCtx)
     return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars);
   });
 
+  luaCtx.writeFunction("getResponseRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistResponseRuleAction> {
+    auto rules = g_respruleactions.getLocal();
+    return getRuleFromSelector(*rules, selector);
+  });
+
   luaCtx.writeFunction("getTopResponseRules", [](boost::optional<unsigned int> top) {
     setLuaNoSideEffect();
     auto rules = g_respruleactions.getLocal();
-    return getTopRules(*rules, (top ? *top : 10));
+    return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
   });
 
   luaCtx.writeFunction("topResponseRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
@@ -375,10 +450,15 @@ void setupLuaRules(LuaContext& luaCtx)
     return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars);
   });
 
+  luaCtx.writeFunction("getSelfAnsweredResponseRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistResponseRuleAction> {
+    auto rules = g_selfansweredrespruleactions.getLocal();
+    return getRuleFromSelector(*rules, selector);
+  });
+
   luaCtx.writeFunction("getTopSelfAnsweredResponseRules", [](boost::optional<unsigned int> top) {
     setLuaNoSideEffect();
     auto rules = g_selfansweredrespruleactions.getLocal();
-    return getTopRules(*rules, (top ? *top : 10));
+    return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
   });
 
   luaCtx.writeFunction("topSelfAnsweredResponseRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
index be2e6ebb7c5edbb84cb56c2cf0c96b845f34cfee..56b7421655d453e2fec9f6f57264ff96ddc8b1c6 100644 (file)
@@ -961,7 +961,7 @@ public:
   virtual ~DNSRule ()
   {
   }
-  virtual bool matches(const DNSQuestion* dq) const =0;
+  virtual bool matches(const DNSQuestion* dq) const = 0;
   virtual string toString() const = 0;
   mutable stat_t d_matches{0};
 };
index be3dffaa3f38d20d15e40218dd44c4250774c31c..41f531c5e591c85be961910258ae3aaf174cc85d 100644 (file)
@@ -169,12 +169,62 @@ For Rules related to the incoming query:
 
   Remove all current rules.
 
-.. function:: getAction(n) -> Action
+.. function:: getAction(n) -> DNSDistRuleAction
 
-  Returns the Action associated with rule ``n``.
+  Returns the :class:`DNSDistRuleAction` associated with rule ``n``.
 
   :param int n: The rule number
 
+.. function:: getCacheHitResponseRule(selector) -> DNSDistResponseRuleAction
+
+  .. versionadded:: 1.9.0
+
+  Return the cache-hit response rule corresponding to the selector, if any.
+  The selector can be the position of the rule in the list, as an integer,
+  its name as a string or its UUID as a string as well.
+
+  :param int or str selector: The position in the list, name or UUID of the rule to return.
+
+.. function:: getCacheInsertedResponseRule(selector) -> DNSDistResponseRuleAction
+
+  .. versionadded:: 1.9.0
+
+  Return the cache-inserted response rule corresponding to the selector, if any.
+  The selector can be the position of the rule in the list, as an integer,
+  its name as a string or its UUID as a string as well.
+
+  :param int or str selector: The position in the list, name or UUID of the rule to return.
+
+.. function:: getResponseRule(selector) -> DNSDistResponseRuleAction
+
+  .. versionadded:: 1.9.0
+
+  Return the response rule corresponding to the selector, if any.
+  The selector can be the position of the rule in the list, as an integer,
+  its name as a string or its UUID as a string as well.
+
+  :param int or str selector: The position in the list, name or UUID of the rule to return.
+
+.. function:: getRule(selector) -> DNSDistRuleAction
+
+  .. versionadded:: 1.9.0
+
+  Return the rule corresponding to the selector, if any.
+  The selector can be the position of the rule in the list, as an integer,
+  its name as a string or its UUID as a string as well.
+
+  :param int or str selector: The position in the list, name or UUID of the rule to return.
+
+.. function:: getSelfAnsweredResponseRule(selector) -> DNSDistResponseRuleAction
+
+  .. versionadded:: 1.9.0
+
+  Return the self-answered response rule corresponding to the selector, if any.
+  The selector can be the position of the rule in the list, as an integer,
+  its name as a string or its UUID as a string as well.
+
+  :param int or str selector: The position in the list, name or UUID of the rule to return.
+
 .. function:: mvRule(from, to)
 
   Move rule ``from`` to a position where it is in front of ``to``.
@@ -1802,3 +1852,45 @@ The following actions exist.
   Subsequent rules are processed after this action.
 
   :param int ttl: Cache TTL for temporary failure replies
+
+Objects
+-------
+
+.. class:: DNSDistRuleAction
+
+  .. versionadded:: 1.9.0
+
+  Represents a rule composed of a :class:`DNSRule` selector, to select the queries this applies to,
+  and a :class:`DNSAction` action to apply when the selector matches.
+
+  .. method:: DNSDistRuleAction:getAction()
+
+    Return the :class:`DNSAction` action of this rule.
+
+  .. method:: DNSDistRuleAction:getSelector()
+
+    Return the :class:`DNSRule` selector of this rule.
+
+.. class:: DNSDistResponseRuleAction
+
+  .. versionadded:: 1.9.0
+
+  Represents a rule composed of a :class:`DNSRule` selector, to select the responses this applies to,
+  and a :class:`DNSResponseAction` action to apply when the selector matches.
+
+  .. method:: DNSDistResponseRuleAction:getAction()
+
+    Return the :class:`DNSResponseAction` action of this rule.
+
+  .. method:: DNSDistResponseRuleAction:getSelector()
+
+    Return the :class:`DNSRule` selector of this rule.
+
+.. class:: DNSRule
+
+  .. versionadded:: 1.9.0
+
+  .. method:: DNSRule:getMatches() -> int
+
+    Return the number of times this selector matched a query or a response. Note that if the same selector is reused for different ``DNSDistRuleAction``
+    objects, the counter will be common to all these objects.