d_excludedSubnets.addMask(range);
}
+ void excludeRange(const NetmaskGroup& group)
+ {
+ d_excludedSubnets.addMasks(group, true);
+ }
+
void includeRange(const Netmask& range)
{
d_excludedSubnets.addMask(range, false);
}
+ void includeRange(const NetmaskGroup& group)
+ {
+ d_excludedSubnets.addMasks(group, false);
+ }
+
void excludeDomain(const DNSName& domain)
{
d_excludedDomains.add(domain);
group->setQTypeRate(qtype, rate, warningRate ? *warningRate : 0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None);
}
});
- luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("excludeRange", [](std::shared_ptr<DynBlockRulesGroup>& group, boost::variant<std::string, std::vector<std::pair<int, std::string>>> ranges) {
+ luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>, NetmaskGroup>)>("excludeRange", [](std::shared_ptr<DynBlockRulesGroup>& group, boost::variant<std::string, std::vector<std::pair<int, std::string>>, NetmaskGroup> ranges) {
if (ranges.type() == typeid(std::vector<std::pair<int, std::string>>)) {
for (const auto& range : *boost::get<std::vector<std::pair<int, std::string>>>(&ranges)) {
group->excludeRange(Netmask(range.second));
}
}
+ else if (ranges.type() == typeid(NetmaskGroup)) {
+ group->excludeRange(*boost::get<NetmaskGroup>(&ranges));
+ }
else {
group->excludeRange(Netmask(*boost::get<std::string>(&ranges)));
}
});
- luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("includeRange", [](std::shared_ptr<DynBlockRulesGroup>& group, boost::variant<std::string, std::vector<std::pair<int, std::string>>> ranges) {
+ luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>, NetmaskGroup>)>("includeRange", [](std::shared_ptr<DynBlockRulesGroup>& group, boost::variant<std::string, std::vector<std::pair<int, std::string>>, NetmaskGroup> ranges) {
if (ranges.type() == typeid(std::vector<std::pair<int, std::string>>)) {
for (const auto& range : *boost::get<std::vector<std::pair<int, std::string>>>(&ranges)) {
group->includeRange(Netmask(range.second));
}
}
+ else if (ranges.type() == typeid(NetmaskGroup)) {
+ group->includeRange(*boost::get<NetmaskGroup>(&ranges));
+ }
else {
group->includeRange(Netmask(*boost::get<std::string>(&ranges)));
}
.. versionadded:: 1.3.1
+ .. versionchanged:: 1.6.0
+ This method now accepts a :class:`NetmaskGroup` object.
+
Exclude this range, or list of ranges, meaning that no dynamic block will ever be inserted for clients in that range. Default to empty, meaning rules are applied to all ranges. When used in combination with :meth:`DynBlockRulesGroup:includeRange`, the more specific entry wins.
- :param list netmasks: A netmask, or list of netmasks, as strings, like for example "192.0.2.1/24"
+ :param list netmasks: A :class:`NetmaskGroup` object, or a netmask or list of netmasks as strings, like for example "192.0.2.1/24"
.. method:: DynBlockRulesGroup:includeRange(netmasks)
.. versionadded:: 1.3.1
+ .. versionchanged:: 1.6.0
+ This method now accepts a :class:`NetmaskGroup` object.
+
Include this range, or list of ranges, meaning that rules will be applied to this range. When used in combination with :meth:`DynBlockRulesGroup:excludeRange`, the more specific entry wins.
- :param list netmasks: A netmask, or list of netmasks, as strings, like for example "192.0.2.1/24"
+ :param list netmasks: A :class:`NetmaskGroup` object, or a netmask or list of netmasks as strings, like for example "192.0.2.1/24"
.. method:: DynBlockRulesGroup:toString()
.. class:: DynBPFFilter
- Represents an dynamic eBPF filter, allowing the use of ephemeral rules to an existing eBPF filter.
+ Represents an dynamic eBPF filter, allowing the use of ephemeral rules to an existing eBPF filter. Note that since 1.6.0 the default BPF filter set via :func:`setDefaultBPFFilter` will automatically be used by a :ref:`DynBlockRulesGroup`, becoming the preferred way of dealing with ephemeral rules.
.. method:: DynBPFFilter:purgeExpired()
tree.insert(nm).second=positive;
}
+ void addMasks(const NetmaskGroup& group, boost::optional<bool> positive)
+ {
+ for (const auto& entry : group.tree) {
+ addMask(entry.first, positive ? *positive : entry.second);
+ }
+ }
+
//! Delete this Netmask from the list of possible matches
void deleteMask(const Netmask& nm)
{
self.assertEquals(query, receivedQuery)
self.assertEquals(receivedResponse, receivedResponse)
+class TestDynBlockGroupExcludedViaNMG(DynBlocksTest):
+
+ _dynBlockQPS = 10
+ _dynBlockPeriod = 2
+ _dynBlockDuration = 5
+ _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+ _config_template = """
+ local nmg = newNMG()
+ nmg:addMask("127.0.0.1/32")
+
+ local dbr = dynBlockRulesGroup()
+ dbr:setQueryRate(%d, %d, "Exceeded query rate", %d)
+ dbr:excludeRange(nmg)
+
+ function maintenance()
+ dbr:apply()
+ end
+
+ newServer{address="127.0.0.1:%s"}
+ """
+
+ def testExcluded(self):
+ """
+ Dyn Blocks (group) : Excluded (via NMG) from the dynamic block rules
+ """
+ name = 'excluded-nmg.group.dynblocks.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN')
+ response = dns.message.make_response(query)
+ rrset = dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '192.0.2.1')
+ response.answer.append(rrset)
+
+ allowed = 0
+ sent = 0
+ for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
+ (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+ sent = sent + 1
+ if receivedQuery:
+ receivedQuery.id = query.id
+ self.assertEquals(query, receivedQuery)
+ self.assertEquals(response, receivedResponse)
+ allowed = allowed + 1
+ else:
+ # the query has not reached the responder,
+ # let's clear the response queue
+ self.clearToResponderQueue()
+
+ # we should not have been blocked
+ self.assertEqual(allowed, sent)
+
+ # wait for the maintenance function to run
+ time.sleep(2)
+
+ # we should still not be blocked
+ (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+ receivedQuery.id = query.id
+ self.assertEquals(query, receivedQuery)
+ self.assertEquals(receivedResponse, receivedResponse)
+
class TestDynBlockGroupNoOp(DynBlocksTest):
_dynBlockQPS = 10