From: Remi Gacogne Date: Wed, 20 Feb 2019 10:59:37 +0000 (+0100) Subject: rec: Add statistics about ECS response sizes X-Git-Tag: dnsdist-1.4.0-alpha1~58^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c9783016e198831fe21c1aeddcbcb240dc8964c0;p=thirdparty%2Fpdns.git rec: Add statistics about ECS response sizes --- diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index 64bc3a7511..80d30e5d11 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -3652,6 +3652,7 @@ static int serviceMain(int argc, char*argv[]) SyncRes::s_ecsipv4limit = ::arg().asNum("ecs-ipv4-bits"); SyncRes::s_ecsipv6limit = ::arg().asNum("ecs-ipv6-bits"); + SyncRes::clearECSStats(); if (!::arg().isEmpty("ecs-scope-zero-address")) { ComboAddress scopeZero(::arg()["ecs-scope-zero-address"]); diff --git a/pdns/rec_channel_rec.cc b/pdns/rec_channel_rec.cc index 43de415fd2..488697b19f 100644 --- a/pdns/rec_channel_rec.cc +++ b/pdns/rec_channel_rec.cc @@ -45,10 +45,16 @@ static map > d_get64bitmembers; static pthread_mutex_t d_dynmetricslock = PTHREAD_MUTEX_INITIALIZER; static map* > d_dynmetrics; +static std::set s_expensiveStats = { "cache-bytes", "packetcache-bytes", "special-memory-usage" }; + bool isStatExpensive(const string& name) { - static const std::set 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) @@ -1049,6 +1055,19 @@ void registerAllStats() 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) diff --git a/pdns/recursordist/docs/metrics.rst b/pdns/recursordist/docs/metrics.rst index 6e004f5de8..895f61b8b8 100644 --- a/pdns/recursordist/docs/metrics.rst +++ b/pdns/recursordist/docs/metrics.rst @@ -236,6 +236,14 @@ ecs-responses ^^^^^^^^^^^^^ number of responses received from authoritative servers with an EDNS Client Subnet option we used (since 4.1) +ecs-v4-response-bits-* +^^^^^^^^^^^^^^^^^^^^^^ +number of responses received from authoritative servers with an IPv4 EDNS Client Subnet option we used, of this subnet size (1 to 32). Added in 4.2.0. + +ecs-v6-response-bits-* +^^^^^^^^^^^^^^^^^^^^^^ +number of responses received from authoritative servers with an IPv6 EDNS Client Subnet option we used, of this subnet size (1 to 128). Added in 4.2.0. + edns-ping-matches ^^^^^^^^^^^^^^^^^ number of servers that sent a valid EDNS PING response diff --git a/pdns/recursordist/test-syncres_cc.cc b/pdns/recursordist/test-syncres_cc.cc index 8736f32aee..f66682bacf 100644 --- a/pdns/recursordist/test-syncres_cc.cc +++ b/pdns/recursordist/test-syncres_cc.cc @@ -151,6 +151,8 @@ static void init(bool debug=false) SyncRes::clearFailedServers(); BOOST_CHECK_EQUAL(SyncRes::getFailedServersSize(), 0); + SyncRes::clearECSStats(); + auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dfe.clear(); luaconfsCopy.dsAnchors.clear(); @@ -1079,7 +1081,7 @@ BOOST_AUTO_TEST_CASE(test_glueless_referral) { 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 sr; initSR(sr); @@ -1096,15 +1098,49 @@ BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) { 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 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 sr; initSR(sr); @@ -1139,12 +1175,22 @@ BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) { return 0; }); + SyncRes::s_ecsqueries = 0; + SyncRes::s_ecsresponses = 0; vector 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) { diff --git a/pdns/syncres.cc b/pdns/syncres.cc index 3cf44f16a3..933d32c682 100644 --- a/pdns/syncres.cc +++ b/pdns/syncres.cc @@ -72,6 +72,9 @@ std::atomic SyncRes::s_nodelegated; std::atomic SyncRes::s_unreachables; std::atomic SyncRes::s_ecsqueries; std::atomic SyncRes::s_ecsresponses; +std::map> SyncRes::s_ecsResponsesBySubnetSize4; +std::map> SyncRes::s_ecsResponsesBySubnetSize6; + uint8_t SyncRes::s_ecsipv4limit; uint8_t SyncRes::s_ecsipv6limit; bool SyncRes::s_doIPv6; @@ -2700,6 +2703,14 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, if(ednsmask) { s_ecsresponses++; LOG(prefix<toString()<<" on response"<getBits() > 0) { + if (ednsmask->isIpv4()) { + ++SyncRes::s_ecsResponsesBySubnetSize4.at(ednsmask->getBits()-1); + } + else { + ++SyncRes::s_ecsResponsesBySubnetSize6.at(ednsmask->getBits()-1); + } + } } } diff --git a/pdns/syncres.hh b/pdns/syncres.hh index a19f21e54e..f177f47b5b 100644 --- a/pdns/syncres.hh +++ b/pdns/syncres.hh @@ -558,6 +558,20 @@ public: 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&ret); @@ -686,6 +700,8 @@ public: static std::atomic s_unreachables; static std::atomic s_ecsqueries; static std::atomic s_ecsresponses; + static std::map> s_ecsResponsesBySubnetSize4; + static std::map> s_ecsResponsesBySubnetSize6; static string s_serverID; static unsigned int s_minimumTTL;