const auto& rcodeIt = counters.d_rcodeCounts.find(rcode);
if (rcodeIt != counters.d_rcodeCounts.cend()) {
- if (pair.second.warningRatioExceeded(counters.queries, rcodeIt->second)) {
+ if (pair.second.warningRatioExceeded(counters.responses, rcodeIt->second)) {
handleWarning(blocks, now, requestor, pair.second, updated);
}
- if (pair.second.ratioExceeded(counters.queries, rcodeIt->second)) {
+ if (pair.second.ratioExceeded(counters.responses, rcodeIt->second)) {
addBlock(blocks, now, requestor, pair.second, updated);
break;
}
struct timespec until = now;
until.tv_sec += rule.d_blockDuration;
unsigned int count = 0;
- const auto& got = blocks.lookup(name);
+ /* be careful, if you try to insert a longer suffix
+ lookup() might return a shorter one if it is
+ already in the tree as a final node */
+ const DynBlock* got = blocks.lookup(name);
+ if (got && got->domain != name) {
+ got = nullptr;
+ }
bool expired = false;
if (got) {
return;
}
+ struct timespec responseCutOff = now;
+
d_respRateRule.d_cutOff = d_respRateRule.d_minTime = now;
d_respRateRule.d_cutOff.tv_sec -= d_respRateRule.d_seconds;
+ if (d_respRateRule.d_cutOff < responseCutOff) {
+ responseCutOff = d_respRateRule.d_cutOff;
+ }
d_suffixMatchRule.d_cutOff = d_suffixMatchRule.d_minTime = now;
d_suffixMatchRule.d_cutOff.tv_sec -= d_suffixMatchRule.d_seconds;
+ if (d_suffixMatchRule.d_cutOff < responseCutOff) {
+ responseCutOff = d_suffixMatchRule.d_cutOff;
+ }
for (auto& rule : d_rcodeRules) {
rule.second.d_cutOff = rule.second.d_minTime = now;
rule.second.d_cutOff.tv_sec -= rule.second.d_seconds;
+ if (rule.second.d_cutOff < responseCutOff) {
+ responseCutOff = rule.second.d_cutOff;
+ }
}
for (auto& rule : d_rcodeRatioRules) {
rule.second.d_cutOff = rule.second.d_minTime = now;
rule.second.d_cutOff.tv_sec -= rule.second.d_seconds;
+ if (rule.second.d_cutOff < responseCutOff) {
+ responseCutOff = rule.second.d_cutOff;
+ }
}
for (const auto& shard : g_rings.d_shards) {
continue;
}
+ if (c.when < responseCutOff) {
+ continue;
+ }
+
auto& entry = counts[c.requestor];
- ++entry.queries;
+ ++entry.responses;
+
bool respRateMatches = d_respRateRule.matches(c.when);
bool suffixMatchRuleMatches = d_suffixMatchRule.matches(c.when);
bool rcodeRuleMatches = checkIfResponseCodeMatches(c);
}
}
-std::map<std::string, std::list<std::pair<Netmask, unsigned int>>> DynBlockMaintenance::getTopNetmasks()
+std::map<std::string, std::list<std::pair<Netmask, unsigned int>>> DynBlockMaintenance::getTopNetmasks(size_t topN)
{
std::map<std::string, std::list<std::pair<Netmask, unsigned int>>> results;
- if (s_topN == 0) {
+ if (topN == 0) {
return results;
}
auto blocks = g_dynblockNMG.getLocal();
for (const auto& entry : *blocks) {
auto& topsForReason = results[entry.second.reason];
- if (topsForReason.size() < s_topN || topsForReason.front().second < entry.second.blocks) {
+ if (topsForReason.size() < topN || topsForReason.front().second < entry.second.blocks) {
auto newEntry = std::make_pair(entry.first, entry.second.blocks.load());
- if (topsForReason.size() >= s_topN) {
+ if (topsForReason.size() >= topN) {
topsForReason.pop_front();
}
return results;
}
-std::map<std::string, std::list<std::pair<DNSName, unsigned int>>> DynBlockMaintenance::getTopSuffixes()
+std::map<std::string, std::list<std::pair<DNSName, unsigned int>>> DynBlockMaintenance::getTopSuffixes(size_t topN)
{
std::map<std::string, std::list<std::pair<DNSName, unsigned int>>> results;
- if (s_topN == 0) {
+ if (topN == 0) {
return results;
}
auto blocks = g_dynblockSMT.getLocal();
- blocks->visit([&results](const SuffixMatchTree<DynBlock>& node) {
+ blocks->visit([&results, topN](const SuffixMatchTree<DynBlock>& node) {
auto& topsForReason = results[node.d_value.reason];
- if (topsForReason.size() < DynBlockMaintenance::s_topN || topsForReason.front().second < node.d_value.blocks) {
+ if (topsForReason.size() < topN || topsForReason.front().second < node.d_value.blocks) {
auto newEntry = std::make_pair(node.d_value.domain, node.d_value.blocks.load());
- if (topsForReason.size() >= DynBlockMaintenance::s_topN) {
+ if (topsForReason.size() >= topN) {
topsForReason.pop_front();
}
void DynBlockMaintenance::collectMetrics()
{
MetricsSnapshot snapshot;
- snapshot.smtData = getTopSuffixes();
- snapshot.nmgData = getTopNetmasks();
+ /* over sampling to get entries that are not in the top N
+ every time a chance to be at the end */
+ snapshot.smtData = getTopSuffixes(s_topN * 5);
+ snapshot.nmgData = getTopNetmasks(s_topN * 5);
{
std::lock_guard<std::mutex> lock(s_topsMutex);
/* now we ask for the top 20 offenders for each reason */
StopWatch sw;
sw.start();
- auto top = DynBlockMaintenance::getTopNetmasks();
+ auto top = DynBlockMaintenance::getTopNetmasks(20);
BOOST_REQUIRE_EQUAL(top.size(), 1U);
auto offenders = top.at(reason);
BOOST_REQUIRE_EQUAL(offenders.size(), 20U);
/* now we ask for the top 20 offenders for each reason */
StopWatch sw;
sw.start();
- auto top = DynBlockMaintenance::getTopSuffixes();
+ auto top = DynBlockMaintenance::getTopSuffixes(20);
BOOST_REQUIRE_EQUAL(top.size(), 1U);
auto suffixes = top.at(reason);
BOOST_REQUIRE_EQUAL(suffixes.size(), 20U);
cerr<<"added 1000000 entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
sw.start();
- auto top = DynBlockMaintenance::getTopSuffixes();
+ auto top = DynBlockMaintenance::getTopSuffixes(20);
cerr<<"scanned 1000000 entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
struct timespec expired = now;
BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1000000U);
sw.start();
- auto top = DynBlockMaintenance::getTopNetmasks();
+ auto top = DynBlockMaintenance::getTopNetmasks(20);
cerr<<"scanned "<<g_dynblockNMG.getLocal()->size()<<" entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
struct timespec expired = now;