/* * Copyright (C) 1996-2023 The Squid Software Foundation and contributors * * Squid software is distributed under GPLv2+ license and includes * contributions from numerous individuals and organizations. * Please see the COPYING and CONTRIBUTORS files for details. */ /* DEBUG: section 49 SNMP Interface */ #include "squid.h" #include "cache_snmp.h" #include "CachePeer.h" #include "CachePeers.h" #include "globals.h" #include "mem/Meter.h" #include "mem/Stats.h" #include "mem_node.h" #include "neighbors.h" #include "snmp_agent.h" #include "snmp_core.h" #include "SquidConfig.h" #include "SquidMath.h" #include "stat.h" #include "StatCounters.h" #include "StatHist.h" #include "Store.h" #include "tools.h" #include "util.h" /************************************************************************ SQUID MIB Implementation ************************************************************************/ /* * cacheSystem group */ variable_list * snmp_sysFn(variable_list * Var, snint * ErrP) { variable_list *Answer = nullptr; MemBuf tmp; debugs(49, 5, "snmp_sysFn: Processing request:" << snmpDebugOid(Var->name, Var->name_length, tmp)); *ErrP = SNMP_ERR_NOERROR; switch (Var->name[LEN_SQ_SYS]) { case SYSVMSIZ: Answer = snmp_var_new_integer(Var->name, Var->name_length, mem_node::StoreMemSize() >> 10, ASN_INTEGER); break; case SYSSTOR: Answer = snmp_var_new_integer(Var->name, Var->name_length, Store::Root().currentSize() >> 10, ASN_INTEGER); break; case SYS_UPTIME: Answer = snmp_var_new_integer(Var->name, Var->name_length, (int)(tvSubDsec(squid_start, current_time) * 100), SMI_TIMETICKS); break; default: *ErrP = SNMP_ERR_NOSUCHNAME; break; } return Answer; } /* * cacheConfig group */ variable_list * snmp_confFn(variable_list * Var, snint * ErrP) { variable_list *Answer = nullptr; const char *cp = nullptr; debugs(49, 5, "snmp_confFn: Processing request with magic " << Var->name[8] << "!"); *ErrP = SNMP_ERR_NOERROR; switch (Var->name[LEN_SQ_CONF]) { case CONF_ADMIN: Answer = snmp_var_new(Var->name, Var->name_length); Answer->type = ASN_OCTET_STR; Answer->val_len = strlen(Config.adminEmail); Answer->val.string = (u_char *) xstrdup(Config.adminEmail); break; case CONF_VERSION: Answer = snmp_var_new(Var->name, Var->name_length); Answer->type = ASN_OCTET_STR; Answer->val_len = strlen(APP_SHORTNAME); Answer->val.string = (u_char *) xstrdup(APP_SHORTNAME); break; case CONF_VERSION_ID: Answer = snmp_var_new(Var->name, Var->name_length); Answer->type = ASN_OCTET_STR; Answer->val_len = strlen(VERSION); Answer->val.string = (u_char *) xstrdup(VERSION); break; case CONF_STORAGE: switch (Var->name[LEN_SQ_CONF + 1]) { case CONF_ST_MMAXSZ: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) (Config.memMaxSize >> 20), ASN_INTEGER); break; case CONF_ST_SWMAXSZ: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) (Store::Root().maxSize() >> 20), ASN_INTEGER); break; case CONF_ST_SWHIWM: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) Config.Swap.highWaterMark, ASN_INTEGER); break; case CONF_ST_SWLOWM: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) Config.Swap.lowWaterMark, ASN_INTEGER); break; default: *ErrP = SNMP_ERR_NOSUCHNAME; break; } break; case CONF_LOG_FAC: Answer = snmp_var_new(Var->name, Var->name_length); if (!(cp = Debug::debugOptions)) cp = "None"; Answer->type = ASN_OCTET_STR; Answer->val_len = strlen(cp); Answer->val.string = (u_char *) xstrdup(cp); break; case CONF_UNIQNAME: Answer = snmp_var_new(Var->name, Var->name_length); cp = uniqueHostname(); Answer->type = ASN_OCTET_STR; Answer->val_len = strlen(cp); Answer->val.string = (u_char *) xstrdup(cp); break; default: *ErrP = SNMP_ERR_NOSUCHNAME; break; } return Answer; } /* * cacheMesh group * - cachePeerTable */ variable_list * snmp_meshPtblFn(variable_list * Var, snint * ErrP) { variable_list *Answer = nullptr; Ip::Address laddr; char *cp = nullptr; CachePeer *p = nullptr; debugs(49, 5, "snmp_meshPtblFn: peer " << Var->name[LEN_SQ_MESH + 3] << " requested!"); *ErrP = SNMP_ERR_NOERROR; u_int index = Var->name[LEN_SQ_MESH + 3] ; for (const auto &peer: CurrentCachePeers()) { if (peer->index == index) { laddr = peer->in_addr ; p = peer.get(); break; } } if (p == nullptr) { *ErrP = SNMP_ERR_NOSUCHNAME; return nullptr; } switch (Var->name[LEN_SQ_MESH + 2]) { case MESH_PTBL_INDEX: { // XXX: Should be visible? Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint)p->index, SMI_INTEGER); } break; case MESH_PTBL_NAME: cp = p->host; Answer = snmp_var_new(Var->name, Var->name_length); Answer->type = ASN_OCTET_STR; Answer->val_len = strlen(cp); Answer->val.string = (u_char *) xstrdup(cp); break; case MESH_PTBL_ADDR_TYPE: { int ival; ival = laddr.isIPv4() ? INETADDRESSTYPE_IPV4 : INETADDRESSTYPE_IPV6 ; Answer = snmp_var_new_integer(Var->name, Var->name_length, ival, SMI_INTEGER); } break; case MESH_PTBL_ADDR: { Answer = snmp_var_new(Var->name, Var->name_length); // InetAddress doesn't have its own ASN.1 type, // like IpAddr does (SMI_IPADDRESS) // See: rfc4001.txt Answer->type = ASN_OCTET_STR; char host[MAX_IPSTRLEN]; laddr.toStr(host,MAX_IPSTRLEN); Answer->val_len = strlen(host); Answer->val.string = (u_char *) xstrdup(host); } break; case MESH_PTBL_HTTP: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) p->http_port, ASN_INTEGER); break; case MESH_PTBL_ICP: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) p->icp.port, ASN_INTEGER); break; case MESH_PTBL_TYPE: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) p->type, ASN_INTEGER); break; case MESH_PTBL_STATE: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) neighborUp(p), ASN_INTEGER); break; case MESH_PTBL_SENT: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.pings_sent, SMI_COUNTER32); break; case MESH_PTBL_PACKED: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.pings_acked, SMI_COUNTER32); break; case MESH_PTBL_FETCHES: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.fetches, SMI_COUNTER32); break; case MESH_PTBL_RTT: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.rtt, ASN_INTEGER); break; case MESH_PTBL_IGN: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.ignored_replies, SMI_COUNTER32); break; case MESH_PTBL_KEEPAL_S: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.n_keepalives_sent, SMI_COUNTER32); break; case MESH_PTBL_KEEPAL_R: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.n_keepalives_recv, SMI_COUNTER32); break; default: *ErrP = SNMP_ERR_NOSUCHNAME; break; } return Answer; } variable_list * snmp_prfSysFn(variable_list * Var, snint * ErrP) { variable_list *Answer = nullptr; static struct rusage rusage; debugs(49, 5, "snmp_prfSysFn: Processing request with magic " << Var->name[LEN_SQ_PRF + 1] << "!"); *ErrP = SNMP_ERR_NOERROR; switch (Var->name[LEN_SQ_PRF + 1]) { case PERF_SYS_PF: squid_getrusage(&rusage); Answer = snmp_var_new_integer(Var->name, Var->name_length, rusage_pagefaults(&rusage), SMI_COUNTER32); break; case PERF_SYS_NUMR: Answer = snmp_var_new_integer(Var->name, Var->name_length, IOStats.Http.reads, SMI_COUNTER32); break; case PERF_SYS_MEMUSAGE: { Mem::PoolStats stats; Mem::GlobalStats(stats); Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) stats.meter->alloc.currentLevel() >> 10, ASN_INTEGER); } break; case PERF_SYS_CPUTIME: squid_getrusage(&rusage); Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) rusage_cputime(&rusage), ASN_INTEGER); break; case PERF_SYS_CPUUSAGE: squid_getrusage(&rusage); Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) Math::doublePercent(rusage_cputime(&rusage), tvSubDsec(squid_start, current_time)), ASN_INTEGER); break; case PERF_SYS_MAXRESSZ: squid_getrusage(&rusage); Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) rusage_maxrss(&rusage), ASN_INTEGER); break; case PERF_SYS_CURLRUEXP: /* No global LRU info anymore */ Answer = snmp_var_new_integer(Var->name, Var->name_length, 0, SMI_TIMETICKS); break; case PERF_SYS_CURUNLREQ: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.unlink.requests, SMI_GAUGE32); break; case PERF_SYS_CURUNUSED_FD: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) Squid_MaxFD - Number_FD, SMI_GAUGE32); break; case PERF_SYS_CURRESERVED_FD: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) RESERVED_FD, SMI_GAUGE32); break; case PERF_SYS_CURUSED_FD: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) Number_FD, SMI_GAUGE32); break; case PERF_SYS_CURMAX_FD: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) Biggest_FD, SMI_GAUGE32); break; case PERF_SYS_NUMOBJCNT: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) StoreEntry::inUseCount(), SMI_GAUGE32); break; default: *ErrP = SNMP_ERR_NOSUCHNAME; break; } return Answer; } variable_list * snmp_prfProtoFn(variable_list * Var, snint * ErrP) { variable_list *Answer = nullptr; static StatCounters *f = nullptr; static StatCounters *l = nullptr; double x; int minutes; debugs(49, 5, "snmp_prfProtoFn: Processing request with magic " << Var->name[LEN_SQ_PRF] << "!"); *ErrP = SNMP_ERR_NOERROR; switch (Var->name[LEN_SQ_PRF + 1]) { case PERF_PROTOSTAT_AGGR: /* cacheProtoAggregateStats */ switch (Var->name[LEN_SQ_PRF + 2]) { case PERF_PROTOSTAT_AGGR_HTTP_REQ: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.client_http.requests, SMI_COUNTER32); break; case PERF_PROTOSTAT_AGGR_HTTP_HITS: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.client_http.hits, SMI_COUNTER32); break; case PERF_PROTOSTAT_AGGR_HTTP_ERRORS: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.client_http.errors, SMI_COUNTER32); break; case PERF_PROTOSTAT_AGGR_HTTP_KBYTES_IN: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.client_http.kbytes_in.kb, SMI_COUNTER32); break; case PERF_PROTOSTAT_AGGR_HTTP_KBYTES_OUT: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.client_http.kbytes_out.kb, SMI_COUNTER32); break; case PERF_PROTOSTAT_AGGR_ICP_S: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.icp.pkts_sent, SMI_COUNTER32); break; case PERF_PROTOSTAT_AGGR_ICP_R: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.icp.pkts_recv, SMI_COUNTER32); break; case PERF_PROTOSTAT_AGGR_ICP_SKB: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.icp.kbytes_sent.kb, SMI_COUNTER32); break; case PERF_PROTOSTAT_AGGR_ICP_RKB: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.icp.kbytes_recv.kb, SMI_COUNTER32); break; case PERF_PROTOSTAT_AGGR_REQ: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.server.all.requests, SMI_INTEGER); break; case PERF_PROTOSTAT_AGGR_ERRORS: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.server.all.errors, SMI_INTEGER); break; case PERF_PROTOSTAT_AGGR_KBYTES_IN: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.server.all.kbytes_in.kb, SMI_COUNTER32); break; case PERF_PROTOSTAT_AGGR_KBYTES_OUT: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.server.all.kbytes_out.kb, SMI_COUNTER32); break; case PERF_PROTOSTAT_AGGR_CURSWAP: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) Store::Root().currentSize() >> 10, SMI_GAUGE32); break; case PERF_PROTOSTAT_AGGR_CLIENTS: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) statCounter.client_http.clients, SMI_GAUGE32); break; default: *ErrP = SNMP_ERR_NOSUCHNAME; break; } return Answer; case PERF_PROTOSTAT_MEDIAN: if (Var->name_length == LEN_SQ_PRF + 5) minutes = Var->name[LEN_SQ_PRF + 4]; else break; if ((minutes < 1) || (minutes > 60)) break; f = snmpStatGet(0); l = snmpStatGet(minutes); debugs(49, 8, "median: min= " << minutes << ", " << Var->name[LEN_SQ_PRF + 3] << " l= " << l << " , f = " << f); debugs(49, 8, "median: l= " << l << " , f = " << f); switch (Var->name[LEN_SQ_PRF + 3]) { case PERF_MEDIAN_TIME: x = minutes; break; case PERF_MEDIAN_HTTP_ALL: x = statHistDeltaMedian(l->client_http.allSvcTime, f->client_http.allSvcTime); break; case PERF_MEDIAN_HTTP_MISS: x = statHistDeltaMedian(l->client_http.missSvcTime, f->client_http.missSvcTime); break; case PERF_MEDIAN_HTTP_NM: x = statHistDeltaMedian(l->client_http.nearMissSvcTime, f->client_http.nearMissSvcTime); break; case PERF_MEDIAN_HTTP_HIT: x = statHistDeltaMedian(l->client_http.hitSvcTime, f->client_http.hitSvcTime); break; case PERF_MEDIAN_ICP_QUERY: x = statHistDeltaMedian(l->icp.querySvcTime, f->icp.querySvcTime); break; case PERF_MEDIAN_ICP_REPLY: x = statHistDeltaMedian(l->icp.replySvcTime, f->icp.replySvcTime); break; case PERF_MEDIAN_DNS: x = statHistDeltaMedian(l->dns.svcTime, f->dns.svcTime); break; case PERF_MEDIAN_RHR: x = statRequestHitRatio(minutes); break; case PERF_MEDIAN_BHR: x = statByteHitRatio(minutes); break; case PERF_MEDIAN_HTTP_NH: x = statHistDeltaMedian(l->client_http.nearHitSvcTime, f->client_http.nearHitSvcTime); break; default: *ErrP = SNMP_ERR_NOSUCHNAME; return nullptr; } return snmp_var_new_integer(Var->name, Var->name_length, (snint) x, SMI_INTEGER); } *ErrP = SNMP_ERR_NOSUCHNAME; return nullptr; }