static pthread_mutex_t d_dynmetricslock = PTHREAD_MUTEX_INITIALIZER;
static map<string, std::atomic<unsigned long>* > d_dynmetrics;
+static std::set<std::string> s_expensiveStats = { "cache-bytes", "packetcache-bytes", "special-memory-usage" };
+
bool isStatExpensive(const string& name)
{
- static const std::set<std::string> expensiveStats = { "cache-bytes", "packetcache-bytes", "special-memory-usage" };
- return expensiveStats.count(name) != 0;
+ return s_expensiveStats.count(name) != 0;
+}
+
+void markStatAsExpensive(const string& name)
+{
+ s_expensiveStats.insert(name);
}
static void addGetStat(const string& name, const uint32_t* place)
addGetStat("policy-result-nodata", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NODATA]);
addGetStat("policy-result-truncate", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Truncate]);
addGetStat("policy-result-custom", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Custom]);
+
+ /* make sure that the ECS stats are properly initialized */
+ SyncRes::clearECSStats();
+ for (size_t idx = 0; idx < SyncRes::s_ecsResponsesBySubnetSize4.size(); idx++) {
+ const std::string name = "ecs-v4-response-bits-" + std::to_string(idx + 1);
+ addGetStat(name, &(SyncRes::s_ecsResponsesBySubnetSize4.at(idx)));
+ markStatAsExpensive(name);
+ }
+ for (size_t idx = 0; idx < SyncRes::s_ecsResponsesBySubnetSize6.size(); idx++) {
+ const std::string name = "ecs-v6-response-bits-" + std::to_string(idx + 1);
+ addGetStat(name, &(SyncRes::s_ecsResponsesBySubnetSize6.at(idx)));
+ markStatAsExpensive(name);
+ }
}
static void doExitGeneric(bool nicely)
SyncRes::clearFailedServers();
BOOST_CHECK_EQUAL(SyncRes::getFailedServersSize(), 0);
+ SyncRes::clearECSStats();
+
auto luaconfsCopy = g_luaconfs.getCopy();
luaconfsCopy.dfe.clear();
luaconfsCopy.dsAnchors.clear();
BOOST_CHECK_EQUAL(ret[0].d_name, target);
}
-BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) {
+BOOST_AUTO_TEST_CASE(test_edns_subnet_by_domain) {
std::unique_ptr<SyncRes> sr;
initSR(sr);
BOOST_REQUIRE(srcmask);
BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
+
+ if (isRootServer(ip)) {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
+ addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+
+ /* this one did not use the ECS info */
+ srcmask = boost::none;
+
+ return 1;
+ } else if (ip == ComboAddress("192.0.2.1:53")) {
+
+ setLWResult(res, 0, true, false, false);
+ addRecordToLW(res, domain, QType::A, "192.0.2.2");
+
+ /* this one did, but only up to a precision of /16, not the full /24 */
+ srcmask = Netmask("192.0.0.0/16");
+
+ return 1;
+ }
+
return 0;
});
+ SyncRes::s_ecsqueries = 0;
+ SyncRes::s_ecsresponses = 0;
vector<DNSRecord> ret;
int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
- BOOST_CHECK_EQUAL(res, RCode::ServFail);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_REQUIRE_EQUAL(ret.size(), 1);
+ BOOST_CHECK(ret[0].d_type == QType::A);
+ BOOST_CHECK_EQUAL(ret[0].d_name, target);
+ BOOST_CHECK_EQUAL(SyncRes::s_ecsqueries, 2);
+ BOOST_CHECK_EQUAL(SyncRes::s_ecsresponses, 1);
+ for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize4) {
+ BOOST_CHECK_EQUAL(entry.second, entry.first == 15 ? 1 : 0);
+ }
+ for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize6) {
+ BOOST_CHECK_EQUAL(entry.second, 0);
+ }
}
-BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) {
+BOOST_AUTO_TEST_CASE(test_edns_subnet_by_addr) {
std::unique_ptr<SyncRes> sr;
initSR(sr);
return 0;
});
+ SyncRes::s_ecsqueries = 0;
+ SyncRes::s_ecsresponses = 0;
vector<DNSRecord> ret;
int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_REQUIRE_EQUAL(ret.size(), 1);
BOOST_CHECK(ret[0].d_type == QType::A);
BOOST_CHECK_EQUAL(ret[0].d_name, target);
+ BOOST_CHECK_EQUAL(SyncRes::s_ecsqueries, 1);
+ BOOST_CHECK_EQUAL(SyncRes::s_ecsresponses, 1);
+ for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize4) {
+ BOOST_CHECK_EQUAL(entry.second, 0);
+ }
+ for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize6) {
+ BOOST_CHECK_EQUAL(entry.second, entry.first == 55 ? 1 : 0);
+ }
}
BOOST_AUTO_TEST_CASE(test_ecs_use_requestor) {
std::atomic<uint64_t> SyncRes::s_unreachables;
std::atomic<uint64_t> SyncRes::s_ecsqueries;
std::atomic<uint64_t> SyncRes::s_ecsresponses;
+std::map<uint8_t, std::atomic<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize4;
+std::map<uint8_t, std::atomic<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize6;
+
uint8_t SyncRes::s_ecsipv4limit;
uint8_t SyncRes::s_ecsipv6limit;
bool SyncRes::s_doIPv6;
if(ednsmask) {
s_ecsresponses++;
LOG(prefix<<qname<<": Received EDNS Client Subnet Mask "<<ednsmask->toString()<<" on response"<<endl);
+ if (ednsmask->getBits() > 0) {
+ if (ednsmask->isIpv4()) {
+ ++SyncRes::s_ecsResponsesBySubnetSize4.at(ednsmask->getBits()-1);
+ }
+ else {
+ ++SyncRes::s_ecsResponsesBySubnetSize6.at(ednsmask->getBits()-1);
+ }
+ }
}
}
s_ecsScopeZero.source = scopeZeroMask;
}
+ static void clearECSStats()
+ {
+ s_ecsqueries.store(0);
+ s_ecsresponses.store(0);
+
+ for (size_t idx = 0; idx < 32; idx++) {
+ SyncRes::s_ecsResponsesBySubnetSize4[idx].store(0);
+ }
+
+ for (size_t idx = 0; idx < 128; idx++) {
+ SyncRes::s_ecsResponsesBySubnetSize6[idx].store(0);
+ }
+ }
+
explicit SyncRes(const struct timeval& now);
int beginResolve(const DNSName &qname, const QType &qtype, uint16_t qclass, vector<DNSRecord>&ret);
static std::atomic<uint64_t> s_unreachables;
static std::atomic<uint64_t> s_ecsqueries;
static std::atomic<uint64_t> s_ecsresponses;
+ static std::map<uint8_t, std::atomic<uint64_t>> s_ecsResponsesBySubnetSize4;
+ static std::map<uint8_t, std::atomic<uint64_t>> s_ecsResponsesBySubnetSize6;
static string s_serverID;
static unsigned int s_minimumTTL;