]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Handle dynamic rules' tag action from Lua
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 14 May 2024 15:38:35 +0000 (17:38 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 16 May 2024 09:10:40 +0000 (11:10 +0200)
pdns/dnsdistdist/dnsdist-dynblocks.cc
pdns/dnsdistdist/dnsdist-dynblocks.hh
pdns/dnsdistdist/dnsdist-lua-ffi.cc
pdns/dnsdistdist/dnsdist-lua-inspection.cc
pdns/dnsdistdist/dnsdist-lua.cc

index a2db09ae94a9da37a23f581163319b24fba288cd..7f4ee53462f6103d91f65f24ce81236dace6a53e 100644 (file)
@@ -214,32 +214,27 @@ static DNSAction::Action getActualAction(const DynBlock& block)
 
 namespace dnsdist::DynamicBlocks
 {
-bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const std::string& reason, unsigned int duration, DNSAction::Action action, bool warning, bool beQuiet, std::shared_ptr<DynBlock::TagSettings> tagSettings)
+bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const timespec& now, const AddressAndPortRange& requestor, DynBlock&& dblock, bool beQuiet)
 {
   unsigned int count = 0;
   bool expired = false;
   bool wasWarning = false;
   bool bpf = false;
-  struct timespec until = now;
-  until.tv_sec += duration;
-
-  DynBlock dblock{reason, until, DNSName(), warning ? DNSAction::Action::NoOp : action};
-  dblock.warning = warning;
 
   const auto& got = blocks.lookup(requestor);
   if (got != nullptr) {
     bpf = got->second.bpf;
 
-    if (warning && !got->second.warning) {
+    if (dblock.warning && !got->second.warning) {
       /* we have an existing entry which is not a warning,
          don't override it */
       return false;
     }
-    if (!warning && got->second.warning) {
+    if (!dblock.warning && got->second.warning) {
       wasWarning = true;
     }
     else {
-      if (until < got->second.until) {
+      if (dblock.until < got->second.until) {
         // had a longer policy
         return false;
       }
@@ -255,9 +250,6 @@ bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const
   }
 
   dblock.blocks = count;
-  if (action == DNSAction::Action::SetTag) {
-    dblock.tagSettings = std::move(tagSettings);
-  }
 
   if (got == nullptr || expired || wasWarning) {
     const auto actualAction = getActualAction(dblock);
@@ -276,7 +268,7 @@ bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const
     }
 
     if (!beQuiet) {
-      warnlog("Inserting %s%sdynamic block for %s for %d seconds: %s", warning ? "(warning) " : "", bpf ? "eBPF " : "", requestor.toString(), duration, reason);
+      warnlog("Inserting %s%sdynamic block for %s for %d seconds: %s", dblock.warning ? "(warning) " : "", bpf ? "eBPF " : "", requestor.toString(), dblock.until.tv_sec - now.tv_sec, dblock.reason);
     }
   }
 
@@ -287,23 +279,20 @@ bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const
   return true;
 }
 
-bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const std::string& reason, unsigned int duration, DNSAction::Action action, bool beQuiet, std::shared_ptr<DynBlock::TagSettings> tagSettings)
+bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const timespec& now, DynBlock&& dblock, bool beQuiet)
 {
-  struct timespec until = now;
-  until.tv_sec += duration;
   unsigned int count = 0;
-  DynBlock dblock{reason, until, name.makeLowerCase(), action};
   /* be careful, if you try to insert a longer suffix
      lookup() might return a shorter one if it is
      already in the tree as a final node */
-  const DynBlock* got = blocks.lookup(name);
-  if (got != nullptr && got->domain != name) {
+  const DynBlock* got = blocks.lookup(dblock.domain);
+  if (got != nullptr && got->domain != dblock.domain) {
     got = nullptr;
   }
   bool expired = false;
 
   if (got != nullptr) {
-    if (until < got->until) {
+    if (dblock.until < got->until) {
       // had a longer policy
       return false;
     }
@@ -318,14 +307,11 @@ bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timesp
   }
 
   dblock.blocks = count;
-  if (action == DNSAction::Action::SetTag) {
-    dblock.tagSettings = std::move(tagSettings);
-  }
 
   if (!beQuiet && (got == nullptr || expired)) {
-    warnlog("Inserting dynamic block for %s for %d seconds: %s", name, duration, reason);
+    warnlog("Inserting dynamic block for %s for %d seconds: %s", dblock.domain, dblock.until.tv_sec - now.tv_sec, dblock.reason);
   }
-  blocks.add(name, std::move(dblock));
+  blocks.add(dblock.domain, std::move(dblock));
   return true;
 }
 }
@@ -338,11 +324,18 @@ void DynBlockRulesGroup::addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock,
     return;
   }
 
+  timespec until{now};
+  until.tv_sec += rule.d_blockDuration;
+  DynBlock dblock{rule.d_blockReason, until, DNSName(), warning ? DNSAction::Action::NoOp : rule.d_action};
+  dblock.warning = warning;
+  if (!warning && rule.d_action == DNSAction::Action::SetTag) {
+    dblock.tagSettings = rule.d_tagSettings;
+  }
   if (!blocks) {
     blocks = g_dynblockNMG.getCopy();
   }
 
-  updated = dnsdist::DynamicBlocks::addOrRefreshBlock(*blocks, now, requestor, rule.d_blockReason, rule.d_blockDuration, rule.d_action, warning, d_beQuiet, rule.d_tagSettings);
+  updated = dnsdist::DynamicBlocks::addOrRefreshBlock(*blocks, now, requestor, std::move(dblock), d_beQuiet);
   if (updated && d_newBlockHook) {
     try {
       d_newBlockHook(dnsdist_ffi_dynamic_block_type_nmt, requestor.toString().c_str(), rule.d_blockReason.c_str(), static_cast<uint8_t>(rule.d_action), rule.d_blockDuration, warning);
@@ -360,7 +353,13 @@ void DynBlockRulesGroup::addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks,
     return;
   }
 
-  updated = dnsdist::DynamicBlocks::addOrRefreshBlockSMT(blocks, now, name, rule.d_blockReason, rule.d_blockDuration, rule.d_action, d_beQuiet, rule.d_tagSettings);
+  timespec until{now};
+  until.tv_sec += rule.d_blockDuration;
+  DynBlock dblock{rule.d_blockReason, until, name.makeLowerCase(), rule.d_action};
+  if (rule.d_action == DNSAction::Action::SetTag) {
+    dblock.tagSettings = rule.d_tagSettings;
+  }
+  updated = dnsdist::DynamicBlocks::addOrRefreshBlockSMT(blocks, now, std::move(dblock), d_beQuiet);
   if (updated && d_newBlockHook) {
     try {
       d_newBlockHook(dnsdist_ffi_dynamic_block_type_smt, name.toString().c_str(), rule.d_blockReason.c_str(), static_cast<uint8_t>(rule.d_action), rule.d_blockDuration, false);
index 1668aa779abca7fd86872d27db95be454bae5ab5..2cb39fcc28ddd3946ee414f614b08ced4e6a1961 100644 (file)
@@ -385,7 +385,7 @@ private:
 
 namespace dnsdist::DynamicBlocks
 {
-bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const std::string& reason, unsigned int duration, DNSAction::Action action, bool warning, bool beQuiet, std::shared_ptr<DynBlock::TagSettings> tagSettings);
-bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const std::string& reason, unsigned int duration, DNSAction::Action action, bool beQuiet, std::shared_ptr<DynBlock::TagSettings> tagSettings);
+bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const timespec& now, const AddressAndPortRange& requestor, DynBlock&& dblock, bool beQuiet);
+bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const timespec& now, DynBlock&& dblock, bool beQuiet);
 }
 #endif /* DISABLE_DYNBLOCKS */
index 65336d1e44c53a6ef89fdc38a0a2995f2f96f522..719fb584fb0322d06bc0e1de66da77413015d590 100644 (file)
@@ -1841,9 +1841,12 @@ bool dnsdist_ffi_dynamic_blocks_add(const char* address, const char* message, ui
 
     timespec now{};
     gettime(&now);
+    timespec until{now};
+    until.tv_sec += duration;
+    DynBlock dblock{message, until, DNSName(), static_cast<DNSAction::Action>(action)};
     auto slow = g_dynblockNMG.getCopy();
 #warning FIXME: need to handle tags
-    if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, message, duration, static_cast<DNSAction::Action>(action), false, false, nullptr)) {
+    if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, std::move(dblock), false)) {
       g_dynblockNMG.setState(slow);
       return true;
     }
@@ -1879,9 +1882,12 @@ bool dnsdist_ffi_dynamic_blocks_smt_add(const char* suffix, const char* message,
 
     timespec now{};
     gettime(&now);
+    timespec until{now};
+    until.tv_sec += duration;
+    DynBlock dblock{message, until, domain, static_cast<DNSAction::Action>(action)};
     auto slow = g_dynblockSMT.getCopy();
 #warning FIXME: need to handle tags
-    if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, domain, message, duration, static_cast<DNSAction::Action>(action), false, nullptr)) {
+    if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, std::move(dblock), false)) {
       g_dynblockSMT.setState(slow);
       return true;
     }
index 23368734ca61e43bc33afddd7594c22a6ef46ec6..6543a26cadcba45d521f5e7219a1d3e6e42a7b09 100644 (file)
@@ -1037,5 +1037,76 @@ void setupLuaInspection(LuaContext& luaCtx)
   luaCtx.registerMember("action", &DynBlock::action);
   luaCtx.registerMember("warning", &DynBlock::warning);
   luaCtx.registerMember("bpf", &DynBlock::bpf);
+
+  luaCtx.writeFunction("addDynBlockSMT",
+                       [](const LuaArray<std::string>& names, const std::string& msg, boost::optional<int> seconds, boost::optional<DNSAction::Action> action, DynamicActionOptionalParameters optionalParameters) {
+                         if (names.empty()) {
+                           return;
+                         }
+                         setLuaSideEffect();
+                         timespec now{};
+                         gettime(&now);
+                         unsigned int actualSeconds = seconds ? *seconds : 10;
+                         DynBlockRulesGroup::DynBlockRule rule;
+                         parseDynamicActionOptionalParameters("addDynBlockSMT", rule, action, optionalParameters);
+
+                         bool needUpdate = false;
+                         auto slow = g_dynblockSMT.getCopy();
+                         for (const auto& capair : names) {
+                           DNSName domain(capair.second);
+                           domain.makeUsLowerCase();
+                           timespec until{now};
+                           until.tv_sec += actualSeconds;
+                           DynBlock dblock{msg, until, std::move(domain), action ? *action : DNSAction::Action::None};
+                           dblock.tagSettings = rule.d_tagSettings;
+                           if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, std::move(dblock), false)) {
+                             needUpdate = true;
+                           }
+                         }
+
+                         if (needUpdate) {
+                           g_dynblockSMT.setState(slow);
+                         }
+                       });
+
+  luaCtx.writeFunction("addDynamicBlock",
+                       [](const boost::variant<ComboAddress, std::string>& clientIP, const std::string& msg, const boost::optional<DNSAction::Action> action, const boost::optional<int> seconds, boost::optional<uint8_t> clientIPMask, boost::optional<uint8_t> clientIPPortMask, DynamicActionOptionalParameters optionalParameters) {
+                         setLuaSideEffect();
+
+                         ComboAddress clientIPCA;
+                         if (clientIP.type() == typeid(ComboAddress)) {
+                           clientIPCA = boost::get<ComboAddress>(clientIP);
+                         }
+                         else {
+                           const auto& clientIPStr = boost::get<std::string>(clientIP);
+                           try {
+                             clientIPCA = ComboAddress(clientIPStr);
+                           }
+                           catch (const std::exception& exp) {
+                             errlog("addDynamicBlock: Unable to parse '%s': %s", clientIPStr, exp.what());
+                             return;
+                           }
+                           catch (const PDNSException& exp) {
+                             errlog("addDynamicBlock: Unable to parse '%s': %s", clientIPStr, exp.reason);
+                             return;
+                           }
+                         }
+                         AddressAndPortRange target(clientIPCA, clientIPMask ? *clientIPMask : (clientIPCA.isIPv4() ? 32 : 128), clientIPPortMask ? *clientIPPortMask : 0);
+                         unsigned int actualSeconds = seconds ? *seconds : 10;
+                         DynBlockRulesGroup::DynBlockRule rule;
+                         parseDynamicActionOptionalParameters("addDynBlockSMT", rule, action, optionalParameters);
+
+                         timespec now{};
+                         gettime(&now);
+                         timespec until{now};
+                         until.tv_sec += actualSeconds;
+                         DynBlock dblock{msg, until, DNSName(), action ? *action : DNSAction::Action::None};
+                         dblock.tagSettings = rule.d_tagSettings;
+
+                         auto slow = g_dynblockNMG.getCopy();
+                         if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, std::move(dblock), false)) {
+                           g_dynblockNMG.setState(slow);
+                         }
+                       });
 #endif /* DISABLE_DYNBLOCKS */
 }
index 81ace57ee9592809792df225a8717e530c7a8fdd..a04c67ca4f4f283cc8d3e47405f0e0f7db4d5258 100644 (file)
@@ -1636,66 +1636,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
   });
 #endif /* DISABLE_DEPRECATED_DYNBLOCK */
 
-  luaCtx.writeFunction("addDynBlockSMT",
-                       [](const LuaArray<std::string>& names, const std::string& msg, boost::optional<int> seconds, boost::optional<DNSAction::Action> action) {
-                         if (names.empty()) {
-                           return;
-                         }
-                         setLuaSideEffect();
-                         timespec now{};
-                         gettime(&now);
-                         unsigned int actualSeconds = seconds ? *seconds : 10;
-
-                         bool needUpdate = false;
-                         auto slow = g_dynblockSMT.getCopy();
-                         for (const auto& capair : names) {
-                           DNSName domain(capair.second);
-                           domain.makeUsLowerCase();
-#warning FIXME: need to handle tags
-                           if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, domain, msg, actualSeconds, action ? *action : DNSAction::Action::None, false, nullptr)) {
-                             needUpdate = true;
-                           }
-                         }
-
-                         if (needUpdate) {
-                           g_dynblockSMT.setState(slow);
-                         }
-                       });
-
-  luaCtx.writeFunction("addDynamicBlock",
-                       [](const boost::variant<ComboAddress, std::string>& clientIP, const std::string& msg, const boost::optional<DNSAction::Action> action, const boost::optional<int> seconds, boost::optional<uint8_t> clientIPMask, boost::optional<uint8_t> clientIPPortMask) {
-                         setLuaSideEffect();
-
-                         ComboAddress clientIPCA;
-                         if (clientIP.type() == typeid(ComboAddress)) {
-                           clientIPCA = boost::get<ComboAddress>(clientIP);
-                         }
-                         else {
-                           const auto& clientIPStr = boost::get<std::string>(clientIP);
-                           try {
-                             clientIPCA = ComboAddress(clientIPStr);
-                           }
-                           catch (const std::exception& exp) {
-                             errlog("addDynamicBlock: Unable to parse '%s': %s", clientIPStr, exp.what());
-                             return;
-                           }
-                           catch (const PDNSException& exp) {
-                             errlog("addDynamicBlock: Unable to parse '%s': %s", clientIPStr, exp.reason);
-                             return;
-                           }
-                         }
-                         AddressAndPortRange target(clientIPCA, clientIPMask ? *clientIPMask : (clientIPCA.isIPv4() ? 32 : 128), clientIPPortMask ? *clientIPPortMask : 0);
-                         unsigned int actualSeconds = seconds ? *seconds : 10;
-
-                         timespec now{};
-                         gettime(&now);
-                         auto slow = g_dynblockNMG.getCopy();
-#warning FIXME: need to handle tags
-                         if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, msg, actualSeconds, action ? *action : DNSAction::Action::None, false, false, nullptr)) {
-                           g_dynblockNMG.setState(slow);
-                         }
-                       });
-
   luaCtx.writeFunction("setDynBlocksPurgeInterval", [](uint64_t interval) {
     DynBlockMaintenance::s_expiredDynBlocksPurgeInterval = static_cast<time_t>(interval);
   });