return *rcode;
}
+static uint16_t strToQType(const std::string& context, const std::string& parameterName, const ::rust::String& qtype_rust_string)
+{
+ auto qtype_str = std::string(qtype_rust_string);
+ boost::to_lower(qtype_str);
+ QType qtype;
+ qtype = std::string(qtype_str);
+ if (qtype.getCode() == 0) {
+ return checkedConversionFromStr<uint8_t>(context, parameterName, qtype_rust_string);
+ }
+ return qtype;
+}
+
static std::optional<std::string> loadContentFromConfigurationFile(const std::string& fileName)
{
/* no check on the file size, don't do this with just any file! */
ruleParams.d_tagSettings->d_name = std::string(rule.tag_name);
ruleParams.d_tagSettings->d_value = std::string(rule.tag_value);
}
- dbrgObj->setRCodeRate(checkedConversionFromStr<int>("dynamic-rules.rules.qtype_rate", "qtype", rule.qtype), std::move(ruleParams));
+ dbrgObj->setQTypeRate(strToQType("dynamic-rules.rules.qtype_rate", "qtype", rule.qtype), std::move(ruleParams));
}
else if (rule.rule_type == "cache-miss-ratio") {
DynBlockRulesGroup::DynBlockCacheMissRatioRule ruleParams(std::string(rule.comment), rule.action_duration, rule.ratio, rule.warning_ratio, rule.seconds, rule.action.empty() ? DNSAction::Action::None : DNSAction::typeFromString(std::string(rule.action)), rule.minimum_number_of_responses, rule.minimum_global_cache_hit_ratio);
_webServerAPIKey = 'apisecret'
_webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
_dynBlockQPS = 10
+ _dynBlockANYQPS = 10
_dynBlockPeriod = 2
# this needs to be greater than maintenanceWaitTime
_dynBlockDuration = _maintenanceWaitTime + 2
self.assertEqual(query, receivedQuery)
self.assertEqual(response, receivedResponse)
+ def doTestQTypeRate(self, name):
+ query = dns.message.make_query(name, 'ANY', 'IN')
+ response = dns.message.make_response(query)
+ blockedResponse = dns.message.make_response(query)
+ blockedResponse.set_rcode(dns.rcode.REFUSED)
+
+ 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.assertEqual(query, receivedQuery)
+ self.assertEqual(response, receivedResponse)
+ allowed = allowed + 1
+ else:
+ # the query has not reached the responder,
+ # let's clear the response queue
+ self.clearToResponderQueue()
+
+ # we might be already blocked, but we should have been able to send
+ # at least self._dynBlockQPS queries
+ self.assertGreaterEqual(allowed, self._dynBlockQPS)
+
+ if allowed == sent:
+ waitForMaintenanceToRun()
+
+ # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
+ (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False, timeout=0.5)
+ self.assertEqual(receivedResponse, blockedResponse)
+
+ # wait until we are not blocked anymore
+ time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
+
+ # this one should succeed
+ (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+ receivedQuery.id = query.id
+ self.assertEqual(query, receivedQuery)
+ self.assertEqual(response, receivedResponse)
+
def doTestQRateRCode(self, name, rcode):
query = dns.message.make_query(name, 'A', 'IN')
response = dns.message.make_response(query)
name = 'qrate.group.dynblocks.tests.powerdns.com.'
self.doTestQRate(name)
+class TestDynBlockGroupQTypeRate(DynBlocksTest):
+
+ _config_template = """
+ local dbr = dynBlockRulesGroup()
+ dbr:setQTypeRate(DNSQType.ANY, %d, %d, "Exceeded qtype rate", %d)
+
+ function maintenance()
+ dbr:apply()
+ end
+ setDynBlocksAction(DNSAction.Refused)
+ newServer{address="127.0.0.1:%d"}
+ """
+ _config_params = ['_dynBlockANYQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+
+ def testDynBlocksQTypeRate(self):
+ """
+ Dyn Blocks (Group): QType Rate
+ """
+ name = 'qtype-rate.group.dynblocks.tests.powerdns.com.'
+ self.doTestQTypeRate(name)
+
+class TestDynBlockGroupQTypeRateYAML(DynBlocksTest):
+
+ _yaml_config_template = """---
+dynamic_rules:
+ - name: "Block client generating too many ANY queries"
+ rules:
+ - type: "qtype-rate"
+ rate: %d
+ seconds: %d
+ action_duration: %d
+ comment: "Exceeded ANY rate"
+ action: "Refused"
+ qtype: "ANY"
+
+backends:
+ - address: "127.0.0.1:%d"
+ protocol: Do53
+"""
+ _config_params = []
+ _yaml_config_params = ['_dynBlockANYQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+
+ def testDynBlocksQTypeRate(self):
+ """
+ Dyn Blocks (Group / YAML): QType Rate
+ """
+ name = 'qtype-rate-yaml.group.dynblocks.tests.powerdns.com.'
+ self.doTestQTypeRate(name)
+
class TestDynBlockGroupQPSRefused(DynBlocksTest):
_config_template = """