]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Improve `NetmaskGroupRule`/`SuffixMatchNodeRule`, deprecate `makeRule`
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 16 Nov 2023 12:05:31 +0000 (13:05 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 4 Dec 2023 12:59:42 +0000 (13:59 +0100)
- `NetmaskGroupRule` now accepts a string or list of strings, instead of requiring the use of `newNMG`
- `SuffixMatchNodeRule` also accepts a string or list of strings, instead of requiring the use of `newSuffixMatchNode`
- Passing a string or list of strings to `addAction` is now deprecated
- `makeRule` is now deprecated

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

index d0714c08dcaeeea4f098bf34bda3afad0ea47fb9..dabe0b8dac355009c81010aefcea99e8e6f2d7c5 100644 (file)
@@ -2305,7 +2305,7 @@ static void addAction(GlobalStateHolder<vector<T> > *someRuleActions, const luad
   parseRuleParams(params, uuid, name, creationOrder);
   checkAllParametersConsumed("addAction", params);
 
-  auto rule = makeRule(var);
+  auto rule = makeRule(var, "addAction");
   someRuleActions->modify([&rule, &action, &uuid, creationOrder, &name](vector<T>& ruleactions){
     ruleactions.push_back({std::move(rule), std::move(action), std::move(name), std::move(uuid), creationOrder});
     });
@@ -2350,7 +2350,7 @@ void setupLuaActions(LuaContext& luaCtx)
       parseRuleParams(params, uuid, name, creationOrder);
       checkAllParametersConsumed("newRuleAction", params);
 
-      auto rule = makeRule(dnsrule);
+      auto rule = makeRule(dnsrule, "newRuleAction");
       DNSDistRuleAction ra({std::move(rule), std::move(action), std::move(name), uuid, creationOrder});
       return std::make_shared<DNSDistRuleAction>(ra);
     });
index 37f04218cc6643f56c6d0fe06a519a6cddbaff2d..f3d6dd623cc5a6024942ce5b03a531711a094ab0 100644 (file)
 #include "dnsdist-rules.hh"
 #include "dns_random.hh"
 
-std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var)
+std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var, const std::string& calledFrom)
 {
-  if (var.type() == typeid(std::shared_ptr<DNSRule>))
+  if (var.type() == typeid(std::shared_ptr<DNSRule>)) {
     return *boost::get<std::shared_ptr<DNSRule>>(&var);
+  }
 
+  bool suffixSeen = false;
   SuffixMatchNode smn;
   NetmaskGroup nmg;
-  auto add=[&](string src) {
+  auto add = [&nmg, &smn, &suffixSeen](string src) {
     try {
       nmg.addMask(src); // need to try mask first, all masks are domain names!
-    } catch(...) {
+    } catch (...) {
+      suffixSeen = true;
       smn.add(DNSName(src));
     }
   };
 
-  if (var.type() == typeid(string))
+  if (var.type() == typeid(string)) {
     add(*boost::get<string>(&var));
-
-  else if (var.type() == typeid(LuaArray<std::string>))
-    for(const auto& a : *boost::get<LuaArray<std::string>>(&var))
-      add(a.second);
-
-  else if (var.type() == typeid(DNSName))
+  }
+  else if (var.type() == typeid(LuaArray<std::string>)) {
+    for (const auto& str : *boost::get<LuaArray<std::string>>(&var)) {
+      add(str.second);
+    }
+  }
+  else if (var.type() == typeid(DNSName)) {
     smn.add(*boost::get<DNSName>(&var));
+  }
+  else if (var.type() == typeid(LuaArray<DNSName>)) {
+    smn = SuffixMatchNode();
+    for (const auto& name : *boost::get<LuaArray<DNSName>>(&var)) {
+      smn.add(name.second);
+    }
+  }
 
-  else if (var.type() == typeid(LuaArray<DNSName>))
-    for(const auto& a : *boost::get<LuaArray<DNSName>>(&var))
-      smn.add(a.second);
-
-  if(nmg.empty())
+  if (nmg.empty()) {
     return std::make_shared<SuffixMatchNodeRule>(smn);
-  else
-    return std::make_shared<NetmaskGroupRule>(nmg, true);
+  }
+  if (suffixSeen) {
+    warnlog("At least one parameter to %s has been parsed as a domain name amongst network masks, and will be ignored!", calledFrom);
+  }
+  return std::make_shared<NetmaskGroupRule>(nmg, true);
 }
 
 static boost::uuids::uuid makeRuleID(std::string& id)
@@ -275,7 +285,9 @@ static boost::optional<T> getRuleFromSelector(const std::vector<T>& rules, const
 
 void setupLuaRules(LuaContext& luaCtx)
 {
-  luaCtx.writeFunction("makeRule", makeRule);
+  luaCtx.writeFunction("makeRule", [](const luadnsrule_t& var) -> std::shared_ptr<DNSRule> {
+    return makeRule(var, "makeRule");
+  });
 
   luaCtx.registerFunction<string(std::shared_ptr<DNSRule>::*)()const>("toString", [](const std::shared_ptr<DNSRule>& rule) { return rule->toString(); });
 
@@ -379,7 +391,7 @@ void setupLuaRules(LuaContext& luaCtx)
           for (const auto& pair : newruleactions) {
             const auto& newruleaction = pair.second;
             if (newruleaction->d_action) {
-              auto rule = makeRule(newruleaction->d_rule);
+              auto rule = newruleaction->d_rule;
               gruleactions.push_back({std::move(rule), newruleaction->d_action, newruleaction->d_name, newruleaction->d_id, newruleaction->d_creationOrder});
             }
           }
@@ -508,13 +520,43 @@ void setupLuaRules(LuaContext& luaCtx)
       return std::shared_ptr<DNSRule>(new SNIRule(name));
   });
 
-  luaCtx.writeFunction("SuffixMatchNodeRule", [](const SuffixMatchNode& smn, boost::optional<bool> quiet) {
+  luaCtx.writeFunction("SuffixMatchNodeRule", [](const boost::variant<const SuffixMatchNode&, std::string, const LuaArray<std::string>> names, boost::optional<bool> quiet) {
+    if (names.type() == typeid(string)) {
+      SuffixMatchNode smn;
+      smn.add(DNSName(*boost::get<std::string>(&names)));
       return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false));
-    });
+    }
 
-  luaCtx.writeFunction("NetmaskGroupRule", [](const NetmaskGroup& nmg, boost::optional<bool> src, boost::optional<bool> quiet) {
+    if (names.type() == typeid(LuaArray<std::string>)) {
+      SuffixMatchNode smn;
+      for (const auto& str : *boost::get<const LuaArray<std::string>>(&names)) {
+        smn.add(DNSName(str.second));
+      }
+      return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false));
+    }
+
+    const auto& smn = *boost::get<const SuffixMatchNode&>(&names);
+    return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false));
+  });
+
+  luaCtx.writeFunction("NetmaskGroupRule", [](const boost::variant<const NetmaskGroup&, std::string, const LuaArray<std::string>> netmasks, boost::optional<bool> src, boost::optional<bool> quiet) {
+    if (netmasks.type() == typeid(string)) {
+      NetmaskGroup nmg;
+      nmg.addMask(*boost::get<std::string>(&netmasks));
       return std::shared_ptr<DNSRule>(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false));
-    });
+    }
+
+    if (netmasks.type() == typeid(LuaArray<std::string>)) {
+      NetmaskGroup nmg;
+      for (const auto& str : *boost::get<const LuaArray<std::string>>(&netmasks)) {
+        nmg.addMask(str.second);
+      }
+      return std::shared_ptr<DNSRule>(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false));
+    }
+
+    const auto& nmg = *boost::get<const NetmaskGroup&>(&netmasks);
+    return std::shared_ptr<DNSRule>(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false));
+  });
 
   luaCtx.writeFunction("benchRule", [](std::shared_ptr<DNSRule> rule, boost::optional<unsigned int> times_, boost::optional<string> suffix_)  {
       setLuaNoSideEffect();
index 88439d91cf46a002b436ff836e0a424097a04de1..7dfe0b30b9414984d022a13937c7862e209443f0 100644 (file)
@@ -156,11 +156,12 @@ template <class T> using LuaArray = std::vector<std::pair<int, T>>;
 template <class T> using LuaAssociativeTable = std::unordered_map<std::string, T>;
 template <class T> using LuaTypeOrArrayOf = boost::variant<T, LuaArray<T>>;
 
-using luadnsrule_t = boost::variant<string, LuaArray<std::string>, std::shared_ptr<DNSRule>, DNSName, LuaArray<DNSName>>;
 using luaruleparams_t = LuaAssociativeTable<std::string>;
 using nmts_t = NetmaskTree<DynBlock, AddressAndPortRange>;
 
-std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var);
+using luadnsrule_t = boost::variant<string, LuaArray<std::string>, std::shared_ptr<DNSRule>, DNSName, LuaArray<DNSName>>;
+std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var, const std::string& calledFrom);
+
 void parseRuleParams(boost::optional<luaruleparams_t>& params, boost::uuids::uuid& uuid, std::string& name, uint64_t& creationOrder);
 void checkParameterBound(const std::string& parameter, uint64_t value, size_t max = std::numeric_limits<uint16_t>::max());
 
index 74a5b0c21cd9494f8b2f3b3ed5ea41ac0e7e50f5..22e337814ca5b0414d10a5d939025547516d0a2d 100644 (file)
@@ -74,7 +74,6 @@ The regex is applied case insensitively.
 Alternatively, if compiled in, :func:`RE2Rule` provides similar functionality, but against libre2.
 
 Note that to check if a name is in a list of domains, :func:`SuffixMatchNodeRule` is preferred over complex regular expressions or multiple instances of :func:`RegexRule`.
-The :func:`makeRule` convenience function can be used to create a :func:`SuffixMatchNodeRule`.
 
 Rule Generators
 ---------------
@@ -154,9 +153,13 @@ For Rules related to the incoming query:
   .. versionchanged:: 1.6.0
     Added ``name`` to the ``options``.
 
+  .. versionchanged:: 1.9.0
+    Passing a string or list of strings instead of a :class:`DNSRule` is deprecated, use :func:`NetmaskGroupRule` or :func:`SuffixMatchNodeRule` instead
+
   Add a Rule and Action to the existing rules.
+  If a string (or list of) is passed as the first parameter instead of a :class:`DNSRule`, it behaves as if the string or list of strings was passed to :func:`NetmaskGroupRule` or :func:`SuffixMatchNodeRule`.
 
-  :param DNSrule rule: A DNSRule, e.g. an :func:`AllRule` or a compounded bunch of rules using e.g. :func:`AndRule`
+  :param DNSrule rule: A :class:`DNSRule`, e.g. an :func:`AllRule`, a compounded bunch of rules using e.g. :func:`AndRule`, or a string (or list of) (deprecated since 1.9.0)
   :param action: The action to take
   :param table options: A table with key: value pairs with options.
 
@@ -687,12 +690,16 @@ These ``DNSRule``\ s be one of the following items:
   .. versionchanged:: 1.4.0
     ``quiet`` parameter added
 
-  Matches traffic from/to the network range specified in ``nmg``.
+  .. versionchanged:: 1.9.0
+    The ``nmg`` parameter now accepts a string or a list of strings in addition to a class:`NetmaskGroup` object.
+
+  Matches traffic from/to the network range specified in the ``nmg``, which can be a string, a list of strings,
+  or a :class:`NetmaskGroup` object created via :func:`newNMG`.
 
   Set the ``src`` parameter to false to match ``nmg`` against destination address instead of source address.
   This can be used to differentiate between clients
 
-  :param NetMaskGroup nmg: The NetMaskGroup to match on
+  :param NetmaskGroup nmg: The netmasks to match, can be a string, a list of strings or a :class:`NetmaskGroup` object.
   :param bool src: Whether to match source or destination address of the packet. Defaults to true (matches source)
   :param bool quiet: Do not display the list of matched netmasks in Rules. Default is false.
 
@@ -838,12 +845,16 @@ These ``DNSRule``\ s be one of the following items:
 
 .. function:: SuffixMatchNodeRule(smn[, quiet])
 
+  .. versionchanged:: 1.9.0
+    The ``smn`` parameter now accepts a string or a list of strings in addition to a class:`SuffixMatchNode` object.
+
   Matches based on a group of domain suffixes for rapid testing of membership.
+  The first parameter, ``smn``, can be a string, list of strings or a class:`SuffixMatchNode` object created with :func:`newSuffixMatchNode`.
   Pass true as second parameter to prevent listing of all domains matched.
 
   To match domain names exactly, see :func:`QNameSetRule`.
 
-  :param SuffixMatchNode smn: The SuffixMatchNode to match on
+  :param SuffixMatchNode smn: A string, list of strings, or a :class:`SuffixMatchNode` to match on
   :param bool quiet: Do not display the list of matched domains in Rules. Default is false.
 
 .. function:: TagRule(name [, value])
@@ -917,10 +928,20 @@ Convenience Functions
 
 .. function:: makeRule(rule)
 
-  Make a :func:`NetmaskGroupRule` or a :func:`SuffixMatchNodeRule`, depending on it is called.
+  .. versionchanged:: 1.9.0
+    This function is deprecated, please use :func:`NetmaskGroupRule` or :func:`SuffixMatchNodeRule` instead
+
+  Make a :func:`NetmaskGroupRule` or a :func:`SuffixMatchNodeRule`, depending on how it is called.
+  The `rule` parameter can be a string, or a list of strings, that should contain either:
+
+  * netmasks: in which case it will behave as :func:`NetmaskGroupRule`, or
+  * domain names: in which case it will behave as :func:`SuffixMatchNodeRule`
+
+  Mixing both netmasks and domain names is not supported, and will result in domain names being ignored!
+
   ``makeRule("0.0.0.0/0")`` will for example match all IPv4 traffic, ``makeRule({"be","nl","lu"})`` will match all Benelux DNS traffic.
 
-  :param string rule: A string to convert to a rule.
+  :param string rule: A string, or list of strings, to convert to a rule.
 
 
 Actions