]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Change the bpf:blockRange bpf:allowRange to bpf:addRangeRule
authorY7n05h <Y7n05h@protonmail.com>
Sat, 4 Jun 2022 05:31:37 +0000 (13:31 +0800)
committerY7n05h <Y7n05h@protonmail.com>
Sat, 4 Jun 2022 06:26:22 +0000 (14:26 +0800)
bpf:rmRangeRule bpf:lsRangeRule

Signed-off-by: Y7n05h <Y7n05h@protonmail.com>
pdns/bpf-filter.cc
pdns/bpf-filter.hh
pdns/dnsdist-lua-bindings.cc
pdns/dnsdistdist/docs/reference/ebpf.rst

index 05d283a60ba38dc5b1deaa644de253b1eb562059..6cd85423ba496be97e09ccc4cb2343aeedeb7482 100644 (file)
@@ -192,11 +192,7 @@ struct QNameValue
   uint16_t qtype{0};
 };
 
-struct CounterAndActionValue
-{
-  uint64_t counter{0};
-  BPFFilter::MatchAction action{BPFFilter::MatchAction::Pass};
-};
+using CounterAndActionValue = BPFFilter::CounterAndActionValue;
 
 BPFFilter::Map::Map(const BPFFilter::MapConfiguration& config, BPFFilter::MapFormat format): d_config(config)
 {
@@ -515,7 +511,7 @@ void BPFFilter::unblock(const ComboAddress& addr)
   }
 }
 
-void BPFFilter::block(const Netmask& addr, bool force, BPFFilter::MatchAction action)
+void BPFFilter::addRangeRule(const Netmask& addr, bool force, BPFFilter::MatchAction action)
 {
   CounterAndActionValue value;
 
@@ -528,12 +524,12 @@ void BPFFilter::block(const Netmask& addr, bool force, BPFFilter::MatchAction ac
       throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
     }
     if (map.d_count >= map.d_config.d_maxItems) {
-      throw std::runtime_error("Table full when trying to block " + addr.toString());
+      throw std::runtime_error("Table full when trying to add this rule: " + addr.toString());
     }
 
     res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
-    if (res != -1 && value.action == action && !force) {
-      throw std::runtime_error("Trying to block an already blocked netmask: " + addr.toString());
+    if (((res != -1 && value.action == action) || (res == -1 && value.action == BPFFilter::MatchAction::Pass)) && !force) {
+      throw std::runtime_error("Trying to add a useless rule: " + addr.toString());
     }
 
     value.counter = 0;
@@ -553,12 +549,12 @@ void BPFFilter::block(const Netmask& addr, bool force, BPFFilter::MatchAction ac
       throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
     }
     if (map.d_count >= map.d_config.d_maxItems) {
-      throw std::runtime_error("Table full when trying to block " + addr.toString());
+      throw std::runtime_error("Table full when trying to add this rule: " + addr.toString());
     }
 
     res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
-    if (res != -1 && value.action == action) {
-      throw std::runtime_error("Trying to block an already blocked netmask: " + addr.toString());
+    if (((res != -1 && value.action == action) || (res == -1 && value.action == BPFFilter::MatchAction::Pass)) && !force) {
+      throw std::runtime_error("Trying to add a useless rule: " + addr.toString());
     }
 
     value.counter = 0;
@@ -571,11 +567,11 @@ void BPFFilter::block(const Netmask& addr, bool force, BPFFilter::MatchAction ac
   }
 
   if (res != 0) {
-    throw std::runtime_error("Error adding blocked address " + addr.toString() + ": " + stringerror());
+    throw std::runtime_error("Error adding this rule: " + addr.toString() + ": " + stringerror());
   }
 }
 
-void BPFFilter::allow(const Netmask& addr)
+void BPFFilter::rmRangeRule(const Netmask& addr)
 {
   int res = 0;
   CounterAndActionValue value;
@@ -593,9 +589,7 @@ void BPFFilter::allow(const Netmask& addr)
       --map.d_count;
     }
     else {
-      res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, BPF_NOEXIST);
-      if (res == 0)
-        ++map.d_count;
+      throw std::runtime_error("Cannot remove '" + addr.toString() + "': No such rule");
     }
   }
   else if (addr.isIPv6()) {
@@ -611,14 +605,12 @@ void BPFFilter::allow(const Netmask& addr)
       --map.d_count;
     }
     else {
-      res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, BPF_NOEXIST);
-      if (res == 0)
-        ++map.d_count;
+      throw std::runtime_error("Cannot remove '" + addr.toString() + "': No such rule");
     }
   }
 
   if (res != 0) {
-    throw std::runtime_error("Error removing blocked netmask" + addr.toString() + ": " + stringerror());
+    throw std::runtime_error("Error removing this rule: " + addr.toString() + ": " + stringerror());
   }
 }
 
@@ -756,11 +748,11 @@ std::vector<std::pair<ComboAddress, uint64_t> > BPFFilter::getAddrStats()
   return result;
 }
 
-std::vector<std::pair<Netmask, uint64_t>> BPFFilter::getRangeStats()
+std::vector<std::pair<Netmask, CounterAndActionValue>> BPFFilter::getRangeRule()
 {
   CIDR4 cidr4[2];
   CIDR6 cidr6[2];
-  std::vector<std::pair<Netmask, uint64_t>> result;
+  std::vector<std::pair<Netmask, CounterAndActionValue>> result;
 
   sockaddr_in v4Addr;
   sockaddr_in6 v6Addr;
@@ -780,7 +772,7 @@ std::vector<std::pair<Netmask, uint64_t>> BPFFilter::getRangeStats()
     while (res == 0) {
       if (bpf_lookup_elem(map.d_fd.getHandle(), &cidr4[1], &value) == 0) {
         v4Addr.sin_addr.s_addr = cidr4[1].addr.s_addr;
-        result.emplace_back(Netmask(&v4Addr, cidr4[1].cidr), value.counter);
+        result.emplace_back(Netmask(&v4Addr, cidr4[1].cidr), value);
       }
 
       res = bpf_get_next_key(map.d_fd.getHandle(), &cidr4[1], &cidr4[1]);
@@ -793,7 +785,7 @@ std::vector<std::pair<Netmask, uint64_t>> BPFFilter::getRangeStats()
     while (res == 0) {
       if (bpf_lookup_elem(map.d_fd.getHandle(), &cidr6[1], &value) == 0) {
         v6Addr.sin6_addr = cidr6[1].addr;
-        result.emplace_back(Netmask(&v6Addr, cidr6[1].cidr), value.counter);
+        result.emplace_back(Netmask(&v6Addr, cidr6[1].cidr), value);
       }
 
       res = bpf_get_next_key(map.d_fd.getHandle(), &cidr6[1], &cidr6[1]);
@@ -918,15 +910,19 @@ void BPFFilter::unblock(const DNSName&, uint16_t)
   throw std::runtime_error("eBPF support not enabled");
 }
 
-void BPFFilter::block(const Netmask&, bool, BPFFilter::MatchAction)
+void BPFFilter::addRangeRule(const Netmask&, bool, BPFFilter::MatchAction)
 {
   throw std::runtime_error("eBPF support not enabled");
 }
-void BPFFilter::allow(const Netmask&)
+void BPFFilter::rmRangeRule(const Netmask&)
 {
   throw std::runtime_error("eBPF support not enabled");
 }
 
+std::vector<std::pair<Netmask, CounterAndActionValue>> BPFFilter::getRangeRule(){
+  std::vector<std::pair<Netmask, CounterAndActionValue>> result;
+  return result;
+}
 std::vector<std::pair<ComboAddress, uint64_t> > BPFFilter::getAddrStats()
 {
   std::vector<std::pair<ComboAddress, uint64_t> > result;
index ba69407292a1e47e251a322498288ab528d8d068..10d563aa214b510e943ae18534841fd7dded1fbd 100644 (file)
@@ -51,6 +51,18 @@ public:
     Drop = 1,
     Truncate = 2
   };
+  static std::string toString(MatchAction s) noexcept
+  {
+    switch (s) {
+    case MatchAction::Pass:
+      return "Pass";
+    case MatchAction::Drop:
+      return "Drop";
+    case MatchAction::Truncate:
+      return "Truncat";
+    }
+    return "Unknow";
+  }
 
   struct MapConfiguration
   {
@@ -59,6 +71,12 @@ public:
     MapType d_type;
   };
 
+  struct CounterAndActionValue
+  {
+    uint64_t counter{0};
+    BPFFilter::MatchAction action{BPFFilter::MatchAction::Pass};
+  };
+  
 
   BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external);
   BPFFilter(const BPFFilter&) = delete;
@@ -69,14 +87,14 @@ public:
   void addSocket(int sock);
   void removeSocket(int sock);
   void block(const ComboAddress& addr, MatchAction action);
-  void block(const Netmask& address, bool force, BPFFilter::MatchAction action);
+  void addRangeRule(const Netmask& address, bool force, BPFFilter::MatchAction action);
   void block(const DNSName& qname, MatchAction action, uint16_t qtype=255);
   void unblock(const ComboAddress& addr);
-  void allow(const Netmask& address);
+  void rmRangeRule(const Netmask& address);
   void unblock(const DNSName& qname, uint16_t qtype=255);
 
   std::vector<std::pair<ComboAddress, uint64_t> > getAddrStats();
-  std::vector<std::pair<Netmask,uint64_t>> getRangeStats();
+  std::vector<std::pair<Netmask, CounterAndActionValue>> getRangeRule();
   std::vector<std::tuple<DNSName, uint16_t, uint64_t> > getQNameStats();
 
   uint64_t getHits(const ComboAddress& requestor);
index 9910873231ba3b4c5a264dd6655143f2fbdb79cc..14375dd57f091e3a9b29599cbe3919ea8a349ed5 100644 (file)
@@ -19,6 +19,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
+#include "bpf-filter.hh"
 #include "config.h"
 #include "dnsdist.hh"
 #include "dnsdist-lua.hh"
@@ -500,12 +501,12 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
         }
       }
     });
-  luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)(const string& range, boost::optional<bool> force, boost::optional<uint32_t> action)>("blockRange", [](std::shared_ptr<BPFFilter> bpf, const string& range, boost::optional<bool> force, boost::optional<uint32_t> action) {
+  luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)(const string& range, uint32_t action, boost::optional<bool> force)>("addRangeRule", [](std::shared_ptr<BPFFilter> bpf, const string& range, uint32_t action, boost::optional<bool> force) {
     if (!bpf) {
       return;
     }
     BPFFilter::MatchAction match;
-    switch (action.value_or(1)) {
+    switch (action) {
     case 0:
       match = BPFFilter::MatchAction::Pass;
       break;
@@ -518,7 +519,7 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
     default:
       throw std::runtime_error("Unsupported action for BPFFilter::block");
     }
-    return bpf->block(Netmask(range), force.value_or(false), match);
+    return bpf->addRangeRule(Netmask(range), force.value_or(false), match);
   });
   luaCtx.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const DNSName& qname, boost::optional<uint16_t> qtype, boost::optional<uint32_t> action)>("blockQName", [](std::shared_ptr<BPFFilter> bpf, const DNSName& qname, boost::optional<uint16_t> qtype, boost::optional<uint32_t> action) {
       if (bpf) {
@@ -551,11 +552,28 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
         return bpf->unblock(ca);
       }
     });
-  luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)(const string& range)>("allowRange", [](std::shared_ptr<BPFFilter> bpf, const string& range) {
+  luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)(const string& range)>("rmRangeRule", [](std::shared_ptr<BPFFilter> bpf, const string& range) {
     if (!bpf) {
       return;
     }
-    bpf->allow(Netmask(range));
+    bpf->rmRangeRule(Netmask(range));
+  });
+  luaCtx.registerFunction<std::string (std::shared_ptr<BPFFilter>::*)() const>("lsRangeRule", [](const std::shared_ptr<BPFFilter> bpf) {
+    setLuaNoSideEffect();
+    std::string res;
+    if (!bpf) {
+      return res;
+    }
+    const auto rangeStat = bpf->getRangeRule();
+    for (const auto& value : rangeStat) {
+      if (value.first.isIPv4()) {
+        res += BPFFilter::toString(value.second.action) + "\t " + value.first.toString() + "\n";
+      }
+      else if (value.first.isIPv6()) {
+        res += BPFFilter::toString(value.second.action) + "\t[" + value.first.toString() + "]\n";
+      }
+    }
+    return res;
   });
   luaCtx.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const DNSName& qname, boost::optional<uint16_t> qtype)>("unblockQName", [](std::shared_ptr<BPFFilter> bpf, const DNSName& qname, boost::optional<uint16_t> qtype) {
       if (bpf) {
@@ -576,13 +594,13 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
             res += "[" + value.first.toString() + "]: " + std::to_string(value.second) + "\n";
           }
         }
-        const auto rangeStat = bpf->getRangeStats();
+        const auto rangeStat = bpf->getRangeRule();
         for (const auto& value : rangeStat) {
           if (value.first.isIPv4()) {
-            res += value.first.toString() + ": " + std::to_string(value.second) + "\n";
+            res += BPFFilter::toString(value.second.action) + "\t " + value.first.toString() + ": " + std::to_string(value.second.counter) + "\n";
           }
           else if (value.first.isIPv6()) {
-            res += "[" + value.first.toString() + "]: " + std::to_string(value.second) + "\n";
+            res += BPFFilter::toString(value.second.action) + "\t[" + value.first.toString() + "]: " + std::to_string(value.second.counter) + "\n";
           }
         }
         auto qstats = bpf->getQNameStats();
index 2c4c1d37c865d18dc1c2cad98ba59c5e34083770..a7f85018b5d6e89c786d0acea22e4b329b8e7f18 100644 (file)
@@ -81,7 +81,7 @@ These are all the functions, objects and methods related to the :doc:`../advance
 
     :param ComboAddress address: The address to block
 
-  .. method:: BPFFilter:blockRange(Netmask [, force=false])
+  .. method:: BPFFilter:addRangeRule(Netmask , action [, force=false])
 
   .. versionchanged:: 1.8.0
 
@@ -89,7 +89,8 @@ These are all the functions, objects and methods related to the :doc:`../advance
 
     DNSDist eBPF code first checks if an exact IP match is found, then if a range matches, and finally if a DNSName does.
 
-    :param string Netmask: The ip range to block
+    :param string Netmask: The ip range to block or unblock
+    :param int action: set ``action``  to ``0`` to unblock a range, set ``action`` to ``1`` to block a range.
     :param bool force: When ``force`` is set to true, DNSDist always accepts adding a new item to BPF maps, even if the item to be added may already be included in the larger network range.
 
   .. method:: BPFFilter:blockQName(name [, qtype=255])
@@ -109,16 +110,17 @@ These are all the functions, objects and methods related to the :doc:`../advance
 
     :param ComboAddress address: The address to unblock
 
-  .. method:: BPFFilter:allowRange(Netmask)
+  .. method:: BPFFilter:rmRangeRule(Netmask)
 
   .. versionchanged:: 1.8.0
 
-    Allow all IP address in this range.
-    DNSDist will attempt to delete the item specified by Netmask first, and if no such item can be found, a new item will be inserted to indicate the exception for this subnet.
-    DNSDist eBPF code first checks if an exact IP match is found, then if a range matches, and finally if a DNSName does.
-    If a query coming from an IP or range marked as allowed, but is for a qname for which a DNSName block exists, the packet will be accepted as the first match wins.
+    :param Netmask string: The rule you want to remove
+
+  .. method:: BPFFilter:lsRangeRule()
+
+  .. versionchanged:: 1.8.0
 
-    :param Netmask string: The ip range to unblock
+    List all range rule.
 
   .. method:: BPFFilter:unblockQName(name [, qtype=255])