From: Otto Moerbeek Date: Wed, 26 Mar 2025 09:57:07 +0000 (+0100) Subject: Add metrics for cookies X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=47c456f437347aadf0ccb4099431c98a89d274fb;p=thirdparty%2Fpdns.git Add metrics for cookies --- diff --git a/pdns/recursordist/RECURSOR-MIB.txt b/pdns/recursordist/RECURSOR-MIB.txt index e96ce2760..716da33dd 100644 --- a/pdns/recursordist/RECURSOR-MIB.txt +++ b/pdns/recursordist/RECURSOR-MIB.txt @@ -1302,6 +1302,70 @@ ecsMissing OBJECT-TYPE "Number of answers where ECS info was missing" ::= { stats 153 } +cookieMalformed OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Malformed cookies received" + ::= { stats 154 } + +cookieMatched OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Matching cookies recieved" + ::= { stats 155 } + +cookieMismatchTcp OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Mismatched cookies received over TCP" + ::= { stats 156 } + +cookieMismatchUdp OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Mismatched cookies received over UDP" + ::= { stats 157 } + +cookieNotInReply OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Authoritative serve sent a reply bnack without cookie" + ::= { stats 158 } + +cookieRetry OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Retries because authoritative server sent a BADCOOKIE reply" + ::= { stats 159 } + +cookiesSupported OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of authoritative server IPs marked as supporting cookies" + ::= { stats 160 } + +cookiesUnsupported OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of authoritative server IPs marked as not supporting cookies" + ::= { stats 161 } + --- --- Traps / Notifications --- @@ -1501,7 +1565,15 @@ recGroup OBJECT-GROUP maxChainWeight, chainLimits, tcpOverflow, - ecsMissing + ecsMissing, + cookieMalformed, + cookieMatched, + cookieMismatchTcp, + cookieMismatchUdp, + cookieNotInReply, + cookieRetry, + cookiesSupported, + cookiesUnsupported } STATUS current DESCRIPTION "Objects conformance group for PowerDNS Recursor" diff --git a/pdns/recursordist/lwres.cc b/pdns/recursordist/lwres.cc index c724fa389..432ca1e56 100644 --- a/pdns/recursordist/lwres.cc +++ b/pdns/recursordist/lwres.cc @@ -489,13 +489,18 @@ static std::pair incomingCookie(const OptLog& log, const VLOG(log, "Received cookie info back from " << address.toString() << ": " << received.toDisplayString() << endl); if (received.getClient() == cookieSentOut->getClient()) { VLOG(log, "Client cookie from " << address.toString() << " matched! Storing with localAddress " << localip.toString() << endl); + ++t_Counters.at(rec::Counter::cookieMatched); found->d_localaddress = localip; found->d_cookie = received; + if (found->getSupport() == CookieEntry::Support::Probing) { + ++t_Counters.at(rec::Counter::cookiesSupported); + } found->setSupport(CookieEntry::Support::Supported, now.tv_sec); // check extended error code uint16_t ercode = (edo.d_extRCode << 4) | lwr.d_rcode; if (ercode == ERCode::BADCOOKIE) { lwr.d_validpacket = true; + ++t_Counters.at(rec::Counter::cookieRetry); VLOG(log, "Server " << localip.toString() << " returned BADCOOKIE " << endl); return {true, LWResult::Result::BadCookie}; // We did update the entry, retry should succeed } @@ -505,16 +510,19 @@ static std::pair incomingCookie(const OptLog& log, const // Server responded with a wrong client cookie, fall back to TCP, RFC 7873 5.3 VLOG(log, "Server " << localip.toString() << " responded with wrong client cookie, fall back to TCP" << endl); lwr.d_validpacket = true; + ++t_Counters.at(rec::Counter::cookieMismatchedOverUDP); return {true, LWResult::Result::Spoofed}; } // mismatched cookie when already doing TCP, ignore that VLOG(log, "Server " << localip.toString() << " responded with wrong client cookie over TCP, ignoring that" << endl); + ++t_Counters.at(rec::Counter::cookieMismatchedOverTCP); } } else { VLOG(log, "Malformed cookie in reply from " << address.toString() << ", dropping as if was a timeout" << endl); // Do something special if we get malformed repeatedly? And or consider current status? lwr.d_validpacket = false; + ++t_Counters.at(rec::Counter::cookieMalformed); return {true, LWResult::Result::Timeout}; } break; // only consider first cookie option found, RFC 7873 5.3 @@ -796,6 +804,7 @@ static LWResult::Result asyncresolve(const OptLog& log, const ComboAddress& addr // Case: we sent out a cookie but did not get one back if (cookieSentOut && !cookieFoundInReply && !*chained) { + ++t_Counters.at(rec::Counter::cookieNotInReply); auto lock = s_cookiestore.lock(); auto found = lock->find(address); if (found != lock->end()) { @@ -803,13 +812,14 @@ static LWResult::Result asyncresolve(const OptLog& log, const ComboAddress& addr case CookieEntry::Support::Probing: VLOG(log, "No cookie in repy from " << address.toString() << ", was probing, setting support to Unsupported" << endl); found->setSupport(CookieEntry::Support::Unsupported, now->tv_sec); + ++t_Counters.at(rec::Counter::cookiesUnsupported); break; case CookieEntry::Support::Unsupported: // We could have detected the server does not support cookies in the meantime VLOG(log, "No cookie in repy from " << address.toString() << ", cookie state is Unsupported, fine" << endl); break; case CookieEntry::Support::Supported: - // RFC says: ignore rpolies not containing any cookie info, equivalent to timeout + // RFC says: ignore replies not containing any cookie info, equivalent to timeout VLOG(log, "No cookie in repy from " << address.toString() << ", cookie state is Supported, dropping packet as if it timed out)" << endl); return LWResult::Result::Timeout; break; diff --git a/pdns/recursordist/metrics_table.py b/pdns/recursordist/metrics_table.py index 9bd117049..420297028 100644 --- a/pdns/recursordist/metrics_table.py +++ b/pdns/recursordist/metrics_table.py @@ -1356,6 +1356,60 @@ 'desc': 'Incoming TCP limits reached', 'snmp': 152, }, + { + 'name': 'ecs-missing', + 'lambda': '[] { return g_Counters.sum(rec::Counter::ecsMissingCount); }', + 'desc': 'Number of answers where ECS info was missing', + 'snmp': 153, + }, + { + 'name': 'cookie-malformed', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieMalformed); }', + 'desc': 'Malformed cookies received', + 'snmp': 154, + }, + { + 'name': 'cookie-matched', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieMatched); }', + 'desc': 'Matching cookies recieved', + 'snmp': 155, + }, + { + 'name': 'cookie-mismatch-tcp', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieMismatchedOverTCP); }', + 'desc': 'Mismatched cookies received over TCP', + 'snmp': 156, + }, + { + 'name': 'cookie-mismatch-udp', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieMismatchedOverUDP); }', + 'desc': 'Mismatched cookies received over UDP', + 'snmp': 157, + }, + { + 'name': 'cookie-not-in-reply', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieNotInReply); }', + 'desc': 'Authoritative serve sent a reply bnack without cookie', + 'snmp': 158, + }, + { + 'name': 'cookie-retry', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieRetry); }', + 'desc': 'Retries because authoritative server sent a BADCOOKIE reply', + 'snmp': 159, + }, + { + 'name': 'cookies-supported', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookiesSupported); }', + 'desc': 'Number of authoritative server IPs marked as supporting cookies', + 'snmp': 160, + }, + { + 'name': 'cookies-unsupported', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookiesUnsupported); }', + 'desc': 'Number of authoritative server IPs marked as not supporting cookies', + 'snmp': 161, + }, { 'name': 'remote-logger-count', 'lambda': '''[]() { @@ -1401,10 +1455,4 @@ 'pname': 'proxy-mapping-total-n-0', # For multicounters, state the first # No SNMP }, - { - 'name': 'ecs-missing', - 'lambda': '[] { return g_Counters.sum(rec::Counter::ecsMissingCount); }', - 'desc': 'Number of answers where ECS info was missing', - 'snmp': 153, - }, ] diff --git a/pdns/recursordist/rec-tcounters.hh b/pdns/recursordist/rec-tcounters.hh index 9f637971a..171a286cb 100644 --- a/pdns/recursordist/rec-tcounters.hh +++ b/pdns/recursordist/rec-tcounters.hh @@ -99,6 +99,14 @@ enum class Counter : uint8_t maxChainWeight, chainLimits, ecsMissingCount, + cookieMalformed, + cookieMatched, + cookieMismatchedOverTCP, + cookieMismatchedOverUDP, + cookieNotInReply, + cookieRetry, + cookiesSupported, + cookiesUnsupported, numberOfCounters }; diff --git a/regression-tests.recursor-dnssec/test_SNMP.py b/regression-tests.recursor-dnssec/test_SNMP.py index c55c5818e..34088ba8d 100644 --- a/regression-tests.recursor-dnssec/test_SNMP.py +++ b/regression-tests.recursor-dnssec/test_SNMP.py @@ -21,7 +21,7 @@ class SNMPTest(RecursorTest): """ def _checkStatsValues(self, results): - count = 153 + count = 161 for i in list(range(1, count)): oid = self._snmpOID + '.1.' + str(i) + '.0' self.assertTrue(oid in results)