From b31a0ea8bd88931d87f59622b797abd34d011bc4 Mon Sep 17 00:00:00 2001 From: Y7n05h Date: Sat, 4 Jun 2022 13:31:37 +0800 Subject: [PATCH] dnsdist: Change the bpf:blockRange bpf:allowRange to bpf:addRangeRule bpf:rmRangeRule bpf:lsRangeRule Signed-off-by: Y7n05h --- pdns/bpf-filter.cc | 50 +++++++++++------------- pdns/bpf-filter.hh | 24 ++++++++++-- pdns/dnsdist-lua-bindings.cc | 34 ++++++++++++---- pdns/dnsdistdist/docs/reference/ebpf.rst | 18 +++++---- 4 files changed, 80 insertions(+), 46 deletions(-) diff --git a/pdns/bpf-filter.cc b/pdns/bpf-filter.cc index 05d283a60b..6cd85423ba 100644 --- a/pdns/bpf-filter.cc +++ b/pdns/bpf-filter.cc @@ -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 > BPFFilter::getAddrStats() return result; } -std::vector> BPFFilter::getRangeStats() +std::vector> BPFFilter::getRangeRule() { CIDR4 cidr4[2]; CIDR6 cidr6[2]; - std::vector> result; + std::vector> result; sockaddr_in v4Addr; sockaddr_in6 v6Addr; @@ -780,7 +772,7 @@ std::vector> 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> 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> BPFFilter::getRangeRule(){ + std::vector> result; + return result; +} std::vector > BPFFilter::getAddrStats() { std::vector > result; diff --git a/pdns/bpf-filter.hh b/pdns/bpf-filter.hh index ba69407292..10d563aa21 100644 --- a/pdns/bpf-filter.hh +++ b/pdns/bpf-filter.hh @@ -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& 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 > getAddrStats(); - std::vector> getRangeStats(); + std::vector> getRangeRule(); std::vector > getQNameStats(); uint64_t getHits(const ComboAddress& requestor); diff --git a/pdns/dnsdist-lua-bindings.cc b/pdns/dnsdist-lua-bindings.cc index 9910873231..14375dd57f 100644 --- a/pdns/dnsdist-lua-bindings.cc +++ b/pdns/dnsdist-lua-bindings.cc @@ -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::*)(const string& range, boost::optional force, boost::optional action)>("blockRange", [](std::shared_ptr bpf, const string& range, boost::optional force, boost::optional action) { + luaCtx.registerFunction::*)(const string& range, uint32_t action, boost::optional force)>("addRangeRule", [](std::shared_ptr bpf, const string& range, uint32_t action, boost::optional 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::*)(const DNSName& qname, boost::optional qtype, boost::optional action)>("blockQName", [](std::shared_ptr bpf, const DNSName& qname, boost::optional qtype, boost::optional action) { if (bpf) { @@ -551,11 +552,28 @@ void setupLuaBindings(LuaContext& luaCtx, bool client) return bpf->unblock(ca); } }); - luaCtx.registerFunction::*)(const string& range)>("allowRange", [](std::shared_ptr bpf, const string& range) { + luaCtx.registerFunction::*)(const string& range)>("rmRangeRule", [](std::shared_ptr bpf, const string& range) { if (!bpf) { return; } - bpf->allow(Netmask(range)); + bpf->rmRangeRule(Netmask(range)); + }); + luaCtx.registerFunction::*)() const>("lsRangeRule", [](const std::shared_ptr 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::*)(const DNSName& qname, boost::optional qtype)>("unblockQName", [](std::shared_ptr bpf, const DNSName& qname, boost::optional 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(); diff --git a/pdns/dnsdistdist/docs/reference/ebpf.rst b/pdns/dnsdistdist/docs/reference/ebpf.rst index 2c4c1d37c8..a7f85018b5 100644 --- a/pdns/dnsdistdist/docs/reference/ebpf.rst +++ b/pdns/dnsdistdist/docs/reference/ebpf.rst @@ -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]) -- 2.47.2