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)
{
}
}
-void BPFFilter::block(const Netmask& addr, bool force, BPFFilter::MatchAction action)
+void BPFFilter::addRangeRule(const Netmask& addr, bool force, BPFFilter::MatchAction action)
{
CounterAndActionValue value;
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;
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;
}
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;
--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()) {
--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());
}
}
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;
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]);
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]);
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;
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
{
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;
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);
* 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"
}
}
});
- 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;
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) {
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) {
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();
:param ComboAddress address: The address to block
- .. method:: BPFFilter:blockRange(Netmask [, force=false])
+ .. method:: BPFFilter:addRangeRule(Netmask , action [, force=false])
.. versionchanged:: 1.8.0
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])
: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])