snmp_core.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 49 SNMP support */
10 
11 #include "squid.h"
12 #include "acl/FilledChecklist.h"
13 #include "base/AsyncCallbacks.h"
14 #include "base/CbcPointer.h"
15 #include "base/RunnersRegistry.h"
16 #include "CachePeer.h"
17 #include "CachePeers.h"
18 #include "client_db.h"
19 #include "comm.h"
20 #include "comm/Connection.h"
21 #include "comm/Loops.h"
22 #include "fatal.h"
23 #include "ip/Address.h"
24 #include "ip/tools.h"
25 #include "ipc/StartListening.h"
26 #include "snmp/Forwarder.h"
27 #include "snmp_agent.h"
28 #include "snmp_core.h"
29 #include "SnmpRequest.h"
30 #include "SquidConfig.h"
31 #include "SquidMath.h"
32 #include "tools.h"
33 
35 
38 
41 
42 static mib_tree_entry * snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType = atNone);
43 static mib_tree_entry *snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType, int children,...);
44 static oid *snmpCreateOid(int length,...);
45 mib_tree_entry * snmpLookupNodeStr(mib_tree_entry *entry, const char *str);
46 bool snmpCreateOidFromStr(const char *str, oid **name, int *nl);
48 static oid *static_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn);
49 static oid *time_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn);
50 static oid *peer_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn);
51 static oid *client_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn);
52 static void snmpDecodePacket(SnmpRequest * rq);
53 static void snmpConstructReponse(SnmpRequest * rq);
54 
55 static oid_ParseFn *snmpTreeNext(oid * Current, snint CurrentLen, oid ** Next, snint * NextLen);
56 static oid_ParseFn *snmpTreeGet(oid * Current, snint CurrentLen);
57 static mib_tree_entry *snmpTreeEntry(oid entry, snint len, mib_tree_entry * current);
58 static mib_tree_entry *snmpTreeSiblingEntry(oid entry, snint len, mib_tree_entry * current);
59 extern "C" void snmpSnmplibDebug(int lvl, char *buf);
60 
61 /*
62  * Turns the MIB into a Tree structure. Called during the startup process.
63  */
64 static void
66 {
67  if (!IamWorkerProcess())
68  return;
69 
70  debugs(49, 5, "snmpInit: Building SNMP mib tree structure");
71 
73 
74  /*
75  * This following bit of evil is to get the final node in the "squid" mib
76  * without having a "search" function. A search function should be written
77  * to make this and the other code much less evil.
78  */
79  mib_tree_head = snmpAddNode(snmpCreateOid(1, 1), 1, nullptr, nullptr, atNone, 0);
80 
82  debugs(49, 5, "snmpInit: root is " << mib_tree_head);
83  snmpAddNodeStr("1", 3, nullptr, nullptr);
84 
85  snmpAddNodeStr("1.3", 6, nullptr, nullptr);
86 
87  snmpAddNodeStr("1.3.6", 1, nullptr, nullptr);
88  snmpAddNodeStr("1.3.6.1", 4, nullptr, nullptr);
89  snmpAddNodeStr("1.3.6.1.4", 1, nullptr, nullptr);
90  snmpAddNodeStr("1.3.6.1.4.1", 3495, nullptr, nullptr);
91  mib_tree_entry *m2 = snmpAddNodeStr("1.3.6.1.4.1.3495", 1, nullptr, nullptr);
92 
93  mib_tree_entry *n = snmpLookupNodeStr(nullptr, "1.3.6.1.4.1.3495.1");
94  assert(m2 == n);
95 
96  /* SQ_SYS - 1.3.6.1.4.1.3495.1.1 */
97  snmpAddNodeStr("1.3.6.1.4.1.3495.1", 1, nullptr, nullptr);
98  snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSVMSIZ, snmp_sysFn, static_Inst, atSum);
99  snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSSTOR, snmp_sysFn, static_Inst, atSum);
100  snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYS_UPTIME, snmp_sysFn, static_Inst, atMax);
101 
102  /* SQ_CONF - 1.3.6.1.4.1.3495.1.2 */
103  snmpAddNodeStr("1.3.6.1.4.1.3495.1", 2, nullptr, nullptr);
104  snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_ADMIN, snmp_confFn, static_Inst);
105  snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_VERSION, snmp_confFn, static_Inst);
106  snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_VERSION_ID, snmp_confFn, static_Inst);
107  snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_LOG_FAC, snmp_confFn, static_Inst);
108 
109  /* SQ_CONF + CONF_STORAGE - 1.3.6.1.4.1.3495.1.5 */
110  snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_STORAGE, nullptr, nullptr);
111  snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_MMAXSZ, snmp_confFn, static_Inst, atSum);
112  snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWMAXSZ, snmp_confFn, static_Inst, atSum);
113  snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWHIWM, snmp_confFn, static_Inst, atMin);
114  snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWLOWM, snmp_confFn, static_Inst, atMin);
115 
116  snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_UNIQNAME, snmp_confFn, static_Inst);
117 
118  /* SQ_PRF - 1.3.6.1.4.1.3495.1.3 */
119  snmpAddNodeStr("1.3.6.1.4.1.3495.1", 3, nullptr, nullptr); /* SQ_PRF */
120 
121  /* PERF_SYS - 1.3.6.1.4.1.3495.1.3.1 */
122  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3", PERF_SYS, nullptr, nullptr);
123  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_PF, snmp_prfSysFn, static_Inst, atSum);
124  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMR, snmp_prfSysFn, static_Inst, atSum);
125  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MEMUSAGE, snmp_prfSysFn, static_Inst, atSum);
126  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUTIME, snmp_prfSysFn, static_Inst, atSum);
127  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUUSAGE, snmp_prfSysFn, static_Inst, atSum);
128  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MAXRESSZ, snmp_prfSysFn, static_Inst, atSum);
129  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMOBJCNT, snmp_prfSysFn, static_Inst, atSum);
130  /*
131  Amos comments:
132  The meaning of LRU is "oldest timestamped object in cache, if LRU algorithm is
133  used"...
134  What this SMP support needs to do is aggregate via a special filter equivalent to
135  min() to retain the semantic oldest-object meaning. A special one is needed that
136  works as unsigned and ignores '0' values.
137  */
138  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURLRUEXP, snmp_prfSysFn, static_Inst);
139  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUNLREQ, snmp_prfSysFn, static_Inst, atSum);
142  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUSED_FD, snmp_prfSysFn, static_Inst, atSum);
143  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURMAX_FD, snmp_prfSysFn, static_Inst, atMax);
144 
145  /* PERF_PROTO - 1.3.6.1.4.1.3495.1.3.2 */
146  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3", PERF_PROTO, nullptr, nullptr);
147  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2", PERF_PROTOSTAT_AGGR, nullptr, nullptr);
163 
164  /* Note this is time-series rather than 'static' */
165  /* cacheMedianSvcTable */
166  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2", PERF_PROTOSTAT_MEDIAN, nullptr, nullptr);
167 
168  /* cacheMedianSvcEntry */
169  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2", 1, nullptr, nullptr);
170  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_TIME, snmp_prfProtoFn, time_Inst, atAverage);
171  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_ALL, snmp_prfProtoFn, time_Inst, atAverage);
172  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_MISS, snmp_prfProtoFn, time_Inst, atAverage);
173  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NM, snmp_prfProtoFn, time_Inst, atAverage);
174  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_HIT, snmp_prfProtoFn, time_Inst, atAverage);
175  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_QUERY, snmp_prfProtoFn, time_Inst, atAverage);
176  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_REPLY, snmp_prfProtoFn, time_Inst, atAverage);
177  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_DNS, snmp_prfProtoFn, time_Inst, atAverage);
178  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_RHR, snmp_prfProtoFn, time_Inst, atAverage);
179  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_BHR, snmp_prfProtoFn, time_Inst, atAverage);
180  snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NH, snmp_prfProtoFn, time_Inst, atAverage);
181 
182  /* SQ_NET - 1.3.6.1.4.1.3495.1.4 */
183  snmpAddNodeStr("1.3.6.1.4.1.3495.1", 4, nullptr, nullptr);
184 
185  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_IP_CACHE, nullptr, nullptr);
186  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_ENT, snmp_netIpFn, static_Inst, atSum);
187  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_REQ, snmp_netIpFn, static_Inst, atSum);
188  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_HITS, snmp_netIpFn, static_Inst, atSum);
189  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_PENDHIT, snmp_netIpFn, static_Inst, atSum);
190  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_NEGHIT, snmp_netIpFn, static_Inst, atSum);
191  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_MISS, snmp_netIpFn, static_Inst, atSum);
192  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_GHBN, snmp_netIpFn, static_Inst, atSum);
193  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_LOC, snmp_netIpFn, static_Inst, atSum);
194 
195  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_FQDN_CACHE, nullptr, nullptr);
196  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_ENT, snmp_netFqdnFn, static_Inst, atSum);
197  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_REQ, snmp_netFqdnFn, static_Inst, atSum);
198  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_HITS, snmp_netFqdnFn, static_Inst, atSum);
199  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_PENDHIT, snmp_netFqdnFn, static_Inst, atSum);
200  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_NEGHIT, snmp_netFqdnFn, static_Inst, atSum);
201  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_MISS, snmp_netFqdnFn, static_Inst, atSum);
202  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_GHBN, snmp_netFqdnFn, static_Inst, atSum);
203 
204  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_DNS_CACHE, nullptr, nullptr);
205  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REQ, snmp_netDnsFn, static_Inst, atSum);
206  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REP, snmp_netDnsFn, static_Inst, atSum);
207  snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_SERVERS, snmp_netDnsFn, static_Inst, atSum);
208 
209  /* SQ_MESH - 1.3.6.1.4.1.3495.1.5 */
210  snmpAddNodeStr("1.3.6.1.4.1.3495.1", 5, nullptr, nullptr);
211 
212  /* cachePeerTable - 1.3.6.1.4.1.3495.1.5.1 */
213  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5", MESH_PTBL, nullptr, nullptr);
214 
215  /* CachePeerEntry (version 3) - 1.3.6.1.4.1.3495.1.5.1.3 */
216  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1", 3, nullptr, nullptr);
217  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_INDEX, snmp_meshPtblFn, peer_Inst);
218  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_NAME, snmp_meshPtblFn, peer_Inst);
219  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ADDR_TYPE, snmp_meshPtblFn, peer_Inst);
220  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ADDR, snmp_meshPtblFn, peer_Inst);
221  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_HTTP, snmp_meshPtblFn, peer_Inst);
222  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ICP, snmp_meshPtblFn, peer_Inst);
223  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_TYPE, snmp_meshPtblFn, peer_Inst);
224  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_STATE, snmp_meshPtblFn, peer_Inst);
225  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_SENT, snmp_meshPtblFn, peer_Inst);
226  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_PACKED, snmp_meshPtblFn, peer_Inst);
227  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_FETCHES, snmp_meshPtblFn, peer_Inst);
228  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_RTT, snmp_meshPtblFn, peer_Inst);
229  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_IGN, snmp_meshPtblFn, peer_Inst);
230  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_KEEPAL_S, snmp_meshPtblFn, peer_Inst);
231  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_KEEPAL_R, snmp_meshPtblFn, peer_Inst);
232 
233  /* cacheClientTable - 1.3.6.1.4.1.3495.1.5.2 */
234  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5", MESH_CTBL, nullptr, nullptr);
235 
236  /* BUG 2811: we NEED to create a reliable index for the client DB and make version 3 of the table. */
237  /* for now we have version 2 table with OID capable of mixed IPv4 / IPv6 clients and upgraded address text format. */
238 
239  /* cacheClientEntry - 1.3.6.1.4.1.3495.1.5.2.2 */
240  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2", 2, nullptr, nullptr);
241  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ADDR_TYPE, snmp_meshCtblFn, client_Inst);
242  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ADDR, snmp_meshCtblFn, client_Inst);
243  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTREQ, snmp_meshCtblFn, client_Inst);
244  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTBYTES, snmp_meshCtblFn, client_Inst);
245  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTHITS, snmp_meshCtblFn, client_Inst);
246  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTHITBYTES, snmp_meshCtblFn, client_Inst);
247  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPREQ, snmp_meshCtblFn, client_Inst);
248  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPBYTES, snmp_meshCtblFn, client_Inst);
249  snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPHITS, snmp_meshCtblFn, client_Inst);
251 
252  debugs(49, 9, "snmpInit: Completed SNMP mib tree structure");
253 }
254 
255 static void
257 {
258  if (!IamWorkerProcess())
259  return;
260 
261  if (Config.Port.snmp <= 0)
262  return;
263 
266  snmpIncomingConn->local.port(Config.Port.snmp);
267 
268  if (!Ip::EnableIpv6 && !snmpIncomingConn->local.setIPv4()) {
269  debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << snmpIncomingConn->local << " is not an IPv4 address.");
270  fatal("SNMP port cannot be opened.");
271  }
272  /* split-stack for now requires IPv4-only SNMP */
273  if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && snmpIncomingConn->local.isAnyAddr()) {
274  snmpIncomingConn->local.setIPv4();
275  }
276 
277  auto call = asyncCallbackFun(49, 2, snmpPortOpened);
278  Ipc::StartListening(SOCK_DGRAM, IPPROTO_UDP, snmpIncomingConn, Ipc::fdnInSnmpSocket, call);
279 
283  snmpOutgoingConn->local.port(Config.Port.snmp);
284 
285  if (!Ip::EnableIpv6 && !snmpOutgoingConn->local.setIPv4()) {
286  debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << snmpOutgoingConn->local << " is not an IPv4 address.");
287  fatal("SNMP port cannot be opened.");
288  }
289  /* split-stack for now requires IPv4-only SNMP */
290  if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && snmpOutgoingConn->local.isAnyAddr()) {
291  snmpOutgoingConn->local.setIPv4();
292  }
293  // TODO: Add/use snmpOutgoingPortOpened() instead of snmpPortOpened().
294  auto c = asyncCallbackFun(49, 2, snmpPortOpened);
295  Ipc::StartListening(SOCK_DGRAM, IPPROTO_UDP, snmpOutgoingConn, Ipc::fdnOutSnmpSocket, c);
296  } else {
298  debugs(1, DBG_IMPORTANT, "Sending SNMP messages from " << snmpOutgoingConn->local);
299  }
300 }
301 
302 static void
304 {
305  const auto &conn = answer.conn;
306 
307  if (!Comm::IsConnOpen(conn))
308  fatalf("Cannot open SNMP %s Port",(conn->fd == snmpIncomingConn->fd?"receiving":"sending"));
309 
310  Comm::SetSelect(conn->fd, COMM_SELECT_READ, snmpHandleUdp, nullptr, 0);
311 
312  if (conn->fd == snmpIncomingConn->fd)
313  debugs(1, DBG_IMPORTANT, "Accepting SNMP messages on " << snmpIncomingConn->local);
314  else if (conn->fd == snmpOutgoingConn->fd)
315  debugs(1, DBG_IMPORTANT, "Sending SNMP messages from " << snmpOutgoingConn->local);
316  else
317  fatalf("Lost SNMP port (%d) on FD %d", (int)conn->local.port(), conn->fd);
318 }
319 
320 static void
322 {
323  if (!IamWorkerProcess())
324  return;
325 
327  debugs(49, DBG_IMPORTANT, "Closing SNMP receiving port " << snmpIncomingConn->local);
328  snmpIncomingConn->close();
329  }
330  snmpIncomingConn = nullptr;
331 
333  // Perform OUT port closure so as not to step on IN port when sharing a conn.
334  debugs(49, DBG_IMPORTANT, "Closing SNMP sending port " << snmpOutgoingConn->local);
335  snmpOutgoingConn->close();
336  }
337  snmpOutgoingConn = nullptr;
338 }
339 
340 class SnmpRr : public RegisteredRunner
341 {
342 public:
343  void finalizeConfig() override { snmpInit(); }
344  void useConfig() override { snmpOpenPorts(); }
345  void startReconfigure() override { snmpClosePorts(); }
346  void syncConfig() override { snmpOpenPorts(); }
347  void startShutdown() override { snmpClosePorts(); }
348 };
350 
351 /*
352  * Accept the UDP packet
353  */
354 void
355 snmpHandleUdp(int sock, void *)
356 {
357  static char buf[SNMP_REQUEST_SIZE];
358  Ip::Address from;
359  SnmpRequest *snmp_rq;
360  int len;
361 
362  debugs(49, 5, "snmpHandleUdp: Called.");
363 
364  Comm::SetSelect(sock, COMM_SELECT_READ, snmpHandleUdp, nullptr, 0);
365 
366  memset(buf, '\0', sizeof(buf));
367 
368  len = comm_udp_recvfrom(sock, buf, sizeof(buf)-1, 0, from);
369 
370  if (len > 0) {
371  debugs(49, 3, "snmpHandleUdp: FD " << sock << ": received " << len << " bytes from " << from << ".");
372 
373  snmp_rq = (SnmpRequest *)xcalloc(1, sizeof(SnmpRequest));
374  snmp_rq->buf = (u_char *) buf;
375  snmp_rq->len = len;
376  snmp_rq->sock = sock;
377  snmp_rq->outbuf = (unsigned char *)xmalloc(snmp_rq->outlen = SNMP_REQUEST_SIZE);
378  snmp_rq->from = from;
379  snmpDecodePacket(snmp_rq);
380  xfree(snmp_rq->outbuf);
381  xfree(snmp_rq);
382  } else {
383  int xerrno = errno;
384  debugs(49, DBG_IMPORTANT, "snmpHandleUdp: FD " << sock << " recvfrom: " << xstrerr(xerrno));
385  }
386 }
387 
388 /*
389  * Turn SNMP packet into a PDU, check available ACL's
390  */
391 static void
393 {
394  struct snmp_pdu *PDU;
395  u_char *Community;
396  u_char *buf = rq->buf;
397  int len = rq->len;
398 
399  if (!Config.accessList.snmp) {
400  debugs(49, DBG_IMPORTANT, "WARNING: snmp_access not configured. agent query DENIED from : " << rq->from);
401  return;
402  }
403 
404  debugs(49, 5, "Called.");
405  PDU = snmp_pdu_create(0);
406  /* Always answer on SNMPv1 */
408  Community = snmp_parse(&rq->session, PDU, buf, len);
409 
410  /* Check if we have explicit permission to access SNMP data.
411  * default (set above) is to deny all */
412  if (Community) {
413  ACLFilledChecklist checklist(Config.accessList.snmp, nullptr);
414  checklist.src_addr = rq->from;
415  checklist.snmp_community = (char *) Community;
416 
417  if (checklist.fastCheck().allowed() && (snmp_coexist_V2toV1(PDU))) {
418  rq->community = Community;
419  rq->PDU = PDU;
420  debugs(49, 5, "snmpAgentParse: reqid=[" << PDU->reqid << "]");
422  } else {
423  debugs(49, DBG_IMPORTANT, "WARNING: SNMP agent query DENIED from : " << rq->from);
424  snmp_free_pdu(PDU);
425  }
426  xfree(Community);
427 
428  } else {
429  debugs(49, DBG_IMPORTANT, "WARNING: Failed SNMP agent query from : " << rq->from);
430  snmp_free_pdu(PDU);
431  }
432 }
433 
434 /*
435  * Packet OK, ACL Check OK, Create response.
436  */
437 static void
439 {
440 
441  struct snmp_pdu *RespPDU;
442 
443  debugs(49, 5, "snmpConstructReponse: Called.");
444 
445  if (UsingSmp() && IamWorkerProcess()) {
446  AsyncJob::Start(new Snmp::Forwarder(static_cast<Snmp::Pdu&>(*rq->PDU),
447  static_cast<Snmp::Session&>(rq->session), rq->sock, rq->from));
448  snmp_free_pdu(rq->PDU);
449  return;
450  }
451 
452  RespPDU = snmpAgentResponse(rq->PDU);
453  snmp_free_pdu(rq->PDU);
454 
455  if (RespPDU != nullptr) {
456  if (snmp_build(&rq->session, RespPDU, rq->outbuf, &rq->outlen) == 0)
457  comm_udp_sendto(rq->sock, rq->from, rq->outbuf, rq->outlen);
458  else
459  debugs(49, DBG_IMPORTANT, "ERROR: Failed to encode a response to SNMP agent query from " << rq->from);
460  snmp_free_pdu(RespPDU);
461  }
462 }
463 
464 /*
465  * Decide how to respond to the request, construct a response and
466  * return the response to the requester.
467  */
468 
469 struct snmp_pdu *
471 
472  struct snmp_pdu *Answer = nullptr;
473 
474  debugs(49, 5, "snmpAgentResponse: Called.");
475 
476  if ((Answer = snmp_pdu_create(SNMP_PDU_RESPONSE))) {
477  Answer->reqid = PDU->reqid;
478  Answer->errindex = 0;
479 
480  if (PDU->command == SNMP_PDU_GET || PDU->command == SNMP_PDU_GETNEXT) {
481  /* Indirect way */
482  int get_next = (PDU->command == SNMP_PDU_GETNEXT);
483  variable_list *VarPtr_;
484  variable_list **RespVars = &(Answer->variables);
485  oid_ParseFn *ParseFn;
486  int index = 0;
487  /* Loop through all variables */
488 
489  for (VarPtr_ = PDU->variables; VarPtr_; VarPtr_ = VarPtr_->next_variable) {
490  variable_list *VarPtr = VarPtr_;
491  variable_list *VarNew = nullptr;
492  oid *NextOidName = nullptr;
493  snint NextOidNameLen = 0;
494 
495  ++index;
496 
497  if (get_next)
498  ParseFn = snmpTreeNext(VarPtr->name, VarPtr->name_length, &NextOidName, &NextOidNameLen);
499  else
500  ParseFn = snmpTreeGet(VarPtr->name, VarPtr->name_length);
501 
502  if (ParseFn == nullptr) {
503  Answer->errstat = SNMP_ERR_NOSUCHNAME;
504  debugs(49, 5, "snmpAgentResponse: No such oid. ");
505  } else {
506  if (get_next) {
507  VarPtr = snmp_var_new(NextOidName, NextOidNameLen);
508  xfree(NextOidName);
509  }
510 
511  int * errstatTmp = &(Answer->errstat);
512 
513  VarNew = (*ParseFn) (VarPtr, (snint *) errstatTmp);
514 
515  if (get_next)
516  snmp_var_free(VarPtr);
517  }
518 
519  if ((Answer->errstat != SNMP_ERR_NOERROR) || (VarNew == nullptr)) {
520  Answer->errindex = index;
521  debugs(49, 5, "snmpAgentResponse: error.");
522 
523  if (VarNew)
524  snmp_var_free(VarNew);
525 
526  while ((VarPtr = Answer->variables) != nullptr) {
527  Answer->variables = VarPtr->next_variable;
528  snmp_var_free(VarPtr);
529  }
530 
531  /* Steal the original PDU list of variables for the error response */
532  Answer->variables = PDU->variables;
533 
534  PDU->variables = nullptr;
535 
536  return (Answer);
537  }
538 
539  /* No error. Insert this var at the end, and move on to the next.
540  */
541  *RespVars = VarNew;
542 
543  RespVars = &(VarNew->next_variable);
544  }
545  }
546  }
547 
548  return (Answer);
549 }
550 
551 static oid_ParseFn *
552 snmpTreeGet(oid * Current, snint CurrentLen)
553 {
554  oid_ParseFn *Fn = nullptr;
555  mib_tree_entry *mibTreeEntry = nullptr;
556  int count = 0;
557 
558  debugs(49, 5, "snmpTreeGet: Called");
559 
560  MemBuf tmp;
561  debugs(49, 6, "snmpTreeGet: Current : " << snmpDebugOid(Current, CurrentLen, tmp) );
562 
563  mibTreeEntry = mib_tree_head;
564 
565  if (Current[count] == mibTreeEntry->name[count]) {
566  ++count;
567 
568  while ((mibTreeEntry) && (count < CurrentLen) && (!mibTreeEntry->parsefunction)) {
569  mibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry);
570  ++count;
571  }
572  }
573 
574  if (mibTreeEntry && mibTreeEntry->parsefunction)
575  Fn = mibTreeEntry->parsefunction;
576 
577  debugs(49, 5, "snmpTreeGet: return");
578 
579  return (Fn);
580 }
581 
582 AggrType
583 snmpAggrType(oid* Current, snint CurrentLen)
584 {
585  debugs(49, 5, MYNAME);
586 
587  mib_tree_entry* mibTreeEntry = mib_tree_head;
588  AggrType type = atNone;
589  int count = 0;
590 
591  if (Current[count] == mibTreeEntry->name[count]) {
592  ++count;
593 
594  while (mibTreeEntry != nullptr && count < CurrentLen) {
595  mibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry);
596  if (mibTreeEntry != nullptr)
597  type = mibTreeEntry->aggrType;
598  ++count;
599  }
600  }
601 
602  return type;
603 }
604 
605 static oid_ParseFn *
606 snmpTreeNext(oid * Current, snint CurrentLen, oid ** Next, snint * NextLen)
607 {
608  oid_ParseFn *Fn = nullptr;
609  int count = 0;
610 
611  debugs(49, 5, "snmpTreeNext: Called");
612 
613  MemBuf tmp;
614  debugs(49, 6, "snmpTreeNext: Current : " << snmpDebugOid(Current, CurrentLen, tmp));
615 
616  mib_tree_entry *mibTreeEntry = mib_tree_head;
617 
618  if (mibTreeEntry && Current[count] == mibTreeEntry->name[count]) {
619  ++count;
620 
621  while ((mibTreeEntry) && (count < CurrentLen) && (!mibTreeEntry->parsefunction)) {
622  mib_tree_entry *nextmibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry);
623 
624  if (!nextmibTreeEntry)
625  break;
626  else
627  mibTreeEntry = nextmibTreeEntry;
628 
629  ++count;
630  }
631  debugs(49, 5, "snmpTreeNext: Recursed down to requested object");
632  } else {
633  return nullptr;
634  }
635 
636  if (mibTreeEntry == mib_tree_last)
637  return (Fn);
638 
639  if ((mibTreeEntry) && (mibTreeEntry->parsefunction)) {
640  *NextLen = CurrentLen;
641  *Next = (*mibTreeEntry->instancefunction) (Current, NextLen, mibTreeEntry, &Fn);
642  if (*Next) {
643  debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next, *NextLen, tmp));
644  return (Fn);
645  }
646  }
647 
648  if ((mibTreeEntry) && (mibTreeEntry->parsefunction)) {
649  --count;
650  mib_tree_entry *nextoid = snmpTreeSiblingEntry(Current[count], count, mibTreeEntry->parent);
651  if (nextoid) {
652  debugs(49, 5, "snmpTreeNext: Next OID found for sibling" << nextoid );
653  mibTreeEntry = nextoid;
654  ++count;
655  } else {
656  debugs(49, 5, "snmpTreeNext: Attempting to recurse up for next object");
657 
658  while (!nextoid) {
659  --count;
660 
661  if (mibTreeEntry->parent->parent) {
662  nextoid = mibTreeEntry->parent;
663  mibTreeEntry = snmpTreeEntry(Current[count] + 1, count, nextoid->parent);
664 
665  if (!mibTreeEntry) {
666  mibTreeEntry = nextoid;
667  nextoid = nullptr;
668  }
669  } else {
670  nextoid = mibTreeEntry;
671  mibTreeEntry = nullptr;
672  }
673  }
674  }
675  }
676  while ((mibTreeEntry) && (!mibTreeEntry->parsefunction)) {
677  mibTreeEntry = mibTreeEntry->leaves[0];
678  }
679 
680  if (mibTreeEntry) {
681  *NextLen = mibTreeEntry->len;
682  *Next = (*mibTreeEntry->instancefunction) (mibTreeEntry->name, NextLen, mibTreeEntry, &Fn);
683  }
684 
685  if (*Next) {
686  debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next, *NextLen, tmp));
687  return (Fn);
688  } else
689  return nullptr;
690 }
691 
692 static oid *
693 static_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
694 {
695  oid *instance = nullptr;
696  if (*len <= current->len) {
697  instance = (oid *)xmalloc(sizeof(*name) * (*len + 1));
698  memcpy(instance, name, sizeof(*name) * (*len));
699  instance[*len] = 0;
700  *len += 1;
701  }
702  *Fn = current->parsefunction;
703  return (instance);
704 }
705 
706 static oid *
707 time_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
708 {
709  oid *instance = nullptr;
710  int identifier = 0, loop = 0;
711  int index[TIME_INDEX_LEN] = {TIME_INDEX};
712 
713  if (*len <= current->len) {
714  instance = (oid *)xmalloc(sizeof(*name) * (*len + 1));
715  memcpy(instance, name, sizeof(*name) * (*len));
716  instance[*len] = *index;
717  *len += 1;
718  } else {
719  identifier = name[*len - 1];
720 
721  while ((loop < TIME_INDEX_LEN) && (identifier != index[loop]))
722  ++loop;
723 
724  if (loop < (TIME_INDEX_LEN - 1)) {
725  instance = (oid *)xmalloc(sizeof(*name) * (*len));
726  memcpy(instance, name, sizeof(*name) * (*len));
727  instance[*len - 1] = index[++loop];
728  }
729  }
730 
731  *Fn = current->parsefunction;
732  return (instance);
733 }
734 
735 static oid *
736 peer_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
737 {
738  oid *instance = nullptr;
739  const auto peersAvailable = CurrentCachePeers().size();
740 
741  if (!peersAvailable) {
742  debugs(49, 6, "snmp peer_Inst: No Peers.");
743  current = current->parent->parent->parent->leaves[1];
744  while ((current) && (!current->parsefunction))
745  current = current->leaves[0];
746 
747  if (!current)
748  return (instance);
749 
750  instance = client_Inst(current->name, len, current, Fn);
751  } else if (*len <= current->len) {
752  debugs(49, 6, "snmp peer_Inst: *len <= current->len ???");
753  instance = (oid *)xmalloc(sizeof(*name) * ( *len + 1));
754  memcpy(instance, name, sizeof(*name) * (*len));
755  instance[*len] = 1 ;
756  *len += 1;
757  } else {
758  int no = name[current->len] ;
759  int i;
760  // Note: This works because the Config.peers keeps its index according to its position.
761  for (i = 0; Less(i, peersAvailable) && Less(i, no); ++i);
762 
763  if (Less(i, peersAvailable)) {
764  debugs(49, 6, "snmp peer_Inst: Encode peer #" << i);
765  instance = (oid *)xmalloc(sizeof(*name) * (current->len + 1 ));
766  memcpy(instance, name, (sizeof(*name) * current->len ));
767  instance[current->len] = no + 1 ; // i.e. the next index on cache_peeer table.
768  } else {
769  debugs(49, 6, "snmp peer_Inst: We have " << i << " peers. Can't find #" << no);
770  return (instance);
771  }
772  }
773  *Fn = current->parsefunction;
774  return (instance);
775 }
776 
777 static oid *
778 client_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
779 {
780  oid *instance = nullptr;
781  Ip::Address laddr;
782  Ip::Address *aux;
783  int size = 0;
784  int newshift = 0;
785 
786  if (*len <= current->len) {
787  aux = client_entry(nullptr);
788  if (aux)
789  laddr = *aux;
790  else
791  laddr.setAnyAddr();
792 
793  if (laddr.isIPv4())
794  size = sizeof(in_addr);
795  else
796  size = sizeof(in6_addr);
797 
798  debugs(49, 6, "len" << *len << ", current-len" << current->len << ", addr=" << laddr << ", size=" << size);
799 
800  instance = (oid *)xmalloc(sizeof(*name) * (*len + size ));
801  memcpy(instance, name, (sizeof(*name) * (*len)));
802 
803  if ( !laddr.isAnyAddr() ) {
804  addr2oid(laddr, &instance[ *len]); // the addr
805  *len += size ;
806  }
807  } else {
808  int shift = *len - current->len ; // i.e 4 or 16
809  oid2addr(&name[*len - shift], laddr,shift);
810  aux = client_entry(&laddr);
811  if (aux)
812  laddr = *aux;
813  else
814  laddr.setAnyAddr();
815 
816  if (!laddr.isAnyAddr()) {
817  if (laddr.isIPv4())
818  newshift = sizeof(in_addr);
819  else
820  newshift = sizeof(in6_addr);
821 
822  debugs(49, 6, "len" << *len << ", current-len" << current->len << ", addr=" << laddr << ", newshift=" << newshift);
823 
824  instance = (oid *)xmalloc(sizeof(*name) * (current->len + newshift));
825  memcpy(instance, name, (sizeof(*name) * (current->len)));
826  addr2oid(laddr, &instance[current->len]); // the addr.
827  *len = current->len + newshift ;
828  }
829  }
830 
831  *Fn = current->parsefunction;
832  return (instance);
833 }
834 
835 /*
836  * Utility functions
837  */
838 
839 /*
840  * Tree utility functions.
841  */
842 
843 /*
844  * Returns a sibling object for the requested child object or NULL
845  * if it does not exit
846  */
847 static mib_tree_entry *
849 {
850  mib_tree_entry *next = nullptr;
851  int count = 0;
852 
853  while ((!next) && (count < current->children)) {
854  if (current->leaves[count]->name[len] == entry) {
855  next = current->leaves[count];
856  }
857 
858  ++count;
859  }
860 
861  /* Exactly the sibling on right */
862  if (count < current->children) {
863  next = current->leaves[count];
864  } else {
865  next = nullptr;
866  }
867 
868  return (next);
869 }
870 
871 /*
872  * Returns the requested child object or NULL if it does not exist
873  */
874 static mib_tree_entry *
875 snmpTreeEntry(oid entry, snint len, mib_tree_entry * current)
876 {
877  mib_tree_entry *next = nullptr;
878  int count = 0;
879 
880  while ((!next) && current && (count < current->children)) {
881  if (current->leaves[count]->name[len] == entry) {
882  next = current->leaves[count];
883  }
884 
885  ++count;
886  }
887 
888  return (next);
889 }
890 
891 static void
893 {
894  debugs(49, 5, "snmpAddNodeChild: assigning " << child << " to parent " << entry);
895  entry->leaves = (mib_tree_entry **)xrealloc(entry->leaves, sizeof(mib_tree_entry *) * (entry->children + 1));
896  entry->leaves[entry->children] = child;
897  entry->leaves[entry->children]->parent = entry;
898  ++ entry->children;
899 }
900 
902 snmpLookupNodeStr(mib_tree_entry *root, const char *str)
903 {
904  oid *name;
905  int namelen;
906  mib_tree_entry *e;
907 
908  if (root)
909  e = root;
910  else
911  e = mib_tree_head;
912 
913  if (! snmpCreateOidFromStr(str, &name, &namelen))
914  return nullptr;
915 
916  /* I wish there were some kind of sensible existing tree traversal
917  * routine to use. I'll worry about that later */
918  if (namelen <= 1) {
919  xfree(name);
920  return e; /* XXX it should only be this? */
921  }
922 
923  int i, r = 1;
924  while (r < namelen) {
925 
926  /* Find the child node which matches this */
927  for (i = 0; i < e->children && e->leaves[i]->name[r] != name[r]; ++i) ; // seek-loop
928 
929  /* Are we pointing to that node? */
930  if (i >= e->children)
931  break;
932  assert(e->leaves[i]->name[r] == name[r]);
933 
934  /* Skip to that node! */
935  e = e->leaves[i];
936  ++r;
937  }
938 
939  xfree(name);
940  return e;
941 }
942 
943 bool
944 snmpCreateOidFromStr(const char *str, oid **name, int *nl)
945 {
946  char const *delim = ".";
947 
948  *name = nullptr;
949  *nl = 0;
950  const char *s = str;
951 
952  /* Parse the OID string into oid bits */
953  while (size_t len = strcspn(s, delim)) {
954  *name = (oid*)xrealloc(*name, sizeof(oid) * ((*nl) + 1));
955  (*name)[*nl] = atoi(s); // stops at the '.' delimiter
956  ++(*nl);
957  // exit with true when the last octet has been parsed
958  if (s[len] == '\0')
959  return true;
960  s += len+1;
961  }
962 
963  // if we aborted before the lst octet was found, return false.
964  safe_free(*name);
965  return false;
966 }
967 
968 /*
969  * Create an entry. Return a pointer to the newly created node, or NULL
970  * on failure.
971  */
972 static mib_tree_entry *
973 snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType)
974 {
975  mib_tree_entry *m, *b;
976  oid *n;
977  int nl;
978  char s[1024];
979 
980  /* Find base node */
981  b = snmpLookupNodeStr(mib_tree_head, base_str);
982  if (! b)
983  return nullptr;
984  debugs(49, 5, "snmpAddNodeStr: " << base_str << ": -> " << b);
985 
986  /* Create OID string for new entry */
987  snprintf(s, 1024, "%s.%d", base_str, o);
988  if (! snmpCreateOidFromStr(s, &n, &nl))
989  return nullptr;
990 
991  /* Create a node */
992  m = snmpAddNode(n, nl, parsefunction, instancefunction, aggrType, 0);
993 
994  /* Link it into the existing tree */
995  snmpAddNodeChild(b, m);
996 
997  /* Return the node */
998  return m;
999 }
1000 
1001 /*
1002  * Adds a node to the MIB tree structure and adds the appropriate children
1003  */
1004 static mib_tree_entry *
1005 snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType, int children,...)
1006 {
1007  va_list args;
1008  int loop;
1009  mib_tree_entry *entry = nullptr;
1010  va_start(args, children);
1011 
1012  MemBuf tmp;
1013  debugs(49, 6, "snmpAddNode: Children : " << children << ", Oid : " << snmpDebugOid(name, len, tmp));
1014 
1015  va_start(args, children);
1016  entry = (mib_tree_entry *)xmalloc(sizeof(mib_tree_entry));
1017  entry->name = name;
1018  entry->len = len;
1019  entry->parsefunction = parsefunction;
1020  entry->instancefunction = instancefunction;
1021  entry->children = children;
1022  entry->leaves = nullptr;
1023  entry->aggrType = aggrType;
1024 
1025  if (children > 0) {
1026  entry->leaves = (mib_tree_entry **)xmalloc(sizeof(mib_tree_entry *) * children);
1027 
1028  for (loop = 0; loop < children; ++loop) {
1029  entry->leaves[loop] = va_arg(args, mib_tree_entry *);
1030  entry->leaves[loop]->parent = entry;
1031  }
1032  }
1033 
1034  va_end(args);
1035  return (entry);
1036 }
1037 /* End of tree utility functions */
1038 
1039 /*
1040  * Returns the list of parameters in an oid
1041  */
1042 static oid *
1043 snmpCreateOid(int length,...)
1044 {
1045  va_list args;
1046  oid *new_oid;
1047  int loop;
1048  va_start(args, length);
1049 
1050  new_oid = (oid *)xmalloc(sizeof(oid) * length);
1051 
1052  if (length > 0) {
1053  for (loop = 0; loop < length; ++loop) {
1054  new_oid[loop] = va_arg(args, int);
1055  }
1056  }
1057 
1058  va_end(args);
1059  return (new_oid);
1060 }
1061 
1062 /*
1063  * Debug calls, prints out the OID for debugging purposes.
1064  */
1065 const char *
1066 snmpDebugOid(oid * Name, snint Len, MemBuf &outbuf)
1067 {
1068  char mbuf[16];
1069  int x;
1070  outbuf.reset();
1071 
1072  for (x = 0; x < Len; ++x) {
1073  size_t bytes = snprintf(mbuf, sizeof(mbuf), ".%u", (unsigned int) Name[x]);
1074  outbuf.append(mbuf, bytes);
1075  }
1076  return outbuf.content();
1077 }
1078 
1079 void
1080 snmpSnmplibDebug(int lvl, char *buf)
1081 {
1082  debugs(49, lvl, buf);
1083 }
1084 
1085 /*
1086  IPv4 address: 10.10.0.9 ==>
1087  oid == 10.10.0.9
1088  IPv6 address : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01 ==>
1089  oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1
1090 */
1091 void
1092 addr2oid(Ip::Address &addr, oid * Dest)
1093 {
1094  u_int i ;
1095  u_char *cp = nullptr;
1096  struct in_addr i4addr;
1097  struct in6_addr i6addr;
1099  u_int size = (code == INETADDRESSTYPE_IPV4) ? sizeof(struct in_addr):sizeof(struct in6_addr);
1100  // Dest[0] = code ;
1101  if ( code == INETADDRESSTYPE_IPV4 ) {
1102  addr.getInAddr(i4addr);
1103  cp = (u_char *) &(i4addr.s_addr);
1104  } else {
1105  addr.getInAddr(i6addr);
1106  cp = (u_char *) &i6addr;
1107  }
1108  for ( i=0 ; i < size ; ++i) {
1109  // OID's are in network order
1110  Dest[i] = *cp;
1111  ++cp;
1112  }
1113  MemBuf tmp;
1114  debugs(49, 7, "addr2oid: Dest : " << snmpDebugOid(Dest, size, tmp));
1115 }
1116 
1117 /*
1118  oid == 10.10.0.9 ==>
1119  IPv4 address: 10.10.0.9
1120  oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1 ==>
1121  IPv6 address : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01
1122 */
1123 void
1124 oid2addr(oid * id, Ip::Address &addr, u_int size)
1125 {
1126  struct in_addr i4addr;
1127  struct in6_addr i6addr;
1128  u_int i;
1129  u_char *cp;
1130  if ( size == sizeof(struct in_addr) )
1131  cp = (u_char *) &(i4addr.s_addr);
1132  else
1133  cp = (u_char *) &(i6addr);
1134  MemBuf tmp;
1135  debugs(49, 7, "oid2addr: id : " << snmpDebugOid(id, size, tmp) );
1136  for (i=0 ; i<size; ++i) {
1137  cp[i] = id[i];
1138  }
1139  if ( size == sizeof(struct in_addr) )
1140  addr = i4addr;
1141  else
1142  addr = i6addr;
1143 }
1144 
1145 int
1147 {
1148  const auto checklist = Filled(ch);
1149 
1150  return data->match (checklist->snmp_community);
1151 }
1152 
@ MESH_PTBL_FETCHES
Definition: cache_snmp.h:246
void fatal(const char *message)
Definition: fatal.cc:28
const char * xstrerr(int error)
Definition: xstrerror.cc:83
@ SYSSTOR
Definition: cache_snmp.h:59
@ SYSVMSIZ
Definition: cache_snmp.h:58
@ PERF_SYS_CURMAX_FD
Definition: cache_snmp.h:125
@ PERF_PROTOSTAT_AGGR_HTTP_ERRORS
Definition: cache_snmp.h:142
AggrType
Definition: snmp_core.h:29
#define SNMP_PDU_RESPONSE
Definition: snmp_pdu.h:94
int snmp_build(struct snmp_session *, struct snmp_pdu *, u_char *, int *)
Definition: snmp_api.c:106
@ PERF_PROTOSTAT_AGGR_ICP_SKB
Definition: cache_snmp.h:147
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
static oid * client_Inst(oid *name, snint *len, mib_tree_entry *current, oid_ParseFn **Fn)
Definition: snmp_core.cc:778
void oid2addr(oid *id, Ip::Address &addr, u_int size)
Definition: snmp_core.cc:1124
static oid * static_Inst(oid *name, snint *len, mib_tree_entry *current, oid_ParseFn **Fn)
Definition: snmp_core.cc:693
@ MESH_PTBL_IGN
Definition: cache_snmp.h:248
const char * snmpDebugOid(oid *Name, snint Len, MemBuf &outbuf)
Definition: snmp_core.cc:1066
#define DBG_CRITICAL
Definition: Stream.h:37
#define SNMP_VERSION_1
Definition: snmp_msg.h:40
#define xmalloc
mib_tree_entry * mib_tree_last
Definition: snmp_core.cc:37
@ PERF_PROTOSTAT_AGGR_CURSWAP
Definition: cache_snmp.h:153
static void snmpDecodePacket(SnmpRequest *rq)
Definition: snmp_core.cc:392
@ MESH_CTBL_ICPHITS
Definition: cache_snmp.h:265
@ PERF_SYS_CURRESERVED_FD
Definition: cache_snmp.h:123
snmp_session wrapper add pack/unpack feature
Definition: Session.h:22
#define TIME_INDEX_LEN
Definition: cache_snmp.h:38
Ip::Address src_addr
static void snmpAddNodeChild(mib_tree_entry *entry, mib_tree_entry *child)
Definition: snmp_core.cc:892
void syncConfig() override
Definition: snmp_core.cc:346
@ PERF_PROTOSTAT_AGGR_ICP_S
Definition: cache_snmp.h:145
@ MESH_CTBL_HTHITS
Definition: cache_snmp.h:261
void snmp_free_pdu(struct snmp_pdu *)
Definition: snmp_pdu.c:284
static void snmpOpenPorts()
Definition: snmp_core.cc:256
oid * name
Definition: snmp_core.h:32
variable_list * snmp_netIpFn(variable_list *Var, snint *ErrP)
Definition: ipcache.cc:1173
struct _mib_tree_entry * parent
Definition: snmp_core.h:40
@ IP_MISS
Definition: cache_snmp.h:194
bool isAnyAddr() const
Definition: Address.cc:190
@ MESH_CTBL_ICPREQ
Definition: cache_snmp.h:263
int comm_udp_sendto(int fd, const Ip::Address &to_addr, const void *buf, int len)
Definition: comm.cc:911
@ PERF_PROTOSTAT_AGGR_ICP_R
Definition: cache_snmp.h:146
struct SquidConfig::@78 Port
@ PERF_PROTOSTAT_AGGR_REQ
Definition: cache_snmp.h:149
@ MESH_PTBL_ADDR
Definition: cache_snmp.h:239
struct SquidConfig::@85 Addrs
@ PERF_PROTOSTAT_AGGR_HTTP_REQ
Definition: cache_snmp.h:140
@ IP_LOC
Definition: cache_snmp.h:196
@ PERF_MEDIAN_DNS
Definition: cache_snmp.h:168
@ PERF_SYS
Definition: cache_snmp.h:105
int children
Definition: snmp_core.h:36
@ NET_DNS_CACHE
Definition: cache_snmp.h:182
oid_ParseFn * parsefunction
Definition: snmp_core.h:34
@ PERF_SYS_CURLRUEXP
Definition: cache_snmp.h:120
@ PERF_SYS_CURUNLREQ
Definition: cache_snmp.h:121
@ PERF_MEDIAN_BHR
Definition: cache_snmp.h:170
static oid * time_Inst(oid *name, snint *len, mib_tree_entry *current, oid_ParseFn **Fn)
Definition: snmp_core.cc:707
@ FQDN_REQ
Definition: cache_snmp.h:204
@ FQDN_ENT
Definition: cache_snmp.h:203
bool getInAddr(struct in_addr &) const
Definition: Address.cc:1032
@ PERF_MEDIAN_ICP_REPLY
Definition: cache_snmp.h:167
int match(ACLChecklist *) override
Matches the actual data in checklist against this Acl::Node.
Definition: snmp_core.cc:1146
Ip::Address * client_entry(Ip::Address *current)
Definition: client_db.cc:421
@ atAverage
Definition: snmp_core.h:29
u_char * snmp_parse(struct snmp_session *, struct snmp_pdu *, u_char *, int)
Definition: snmp_api.c:129
@ PERF_PROTOSTAT_MEDIAN
Definition: cache_snmp.h:133
@ DNS_REQ
Definition: cache_snmp.h:216
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
void startReconfigure() override
Definition: snmp_core.cc:345
void snmpHandleUdp(int sock, void *)
Definition: snmp_core.cc:355
@ PERF_SYS_CPUTIME
Definition: cache_snmp.h:116
@ PERF_MEDIAN_HTTP_NM
Definition: cache_snmp.h:164
#define INETADDRESSTYPE_IPV4
Definition: snmp_vars.h:93
bool IamWorkerProcess()
whether the current process handles HTTP transactions and such
Definition: stub_tools.cc:47
@ PERF_SYS_NUMOBJCNT
Definition: cache_snmp.h:119
Ip::Address from
Definition: SnmpRequest.h:28
Comm::ConnectionPointer snmpOutgoingConn
Definition: snmp_core.cc:40
bool isIPv4() const
Definition: Address.cc:178
@ MESH_PTBL_PACKED
Definition: cache_snmp.h:245
static mib_tree_entry * snmpAddNode(oid *name, int len, oid_ParseFn *parsefunction, instance_Fn *instancefunction, AggrType aggrType, int children,...)
Definition: snmp_core.cc:1005
variable_list * snmp_confFn(variable_list *Var, snint *ErrP)
Definition: snmp_agent.cc:83
u_char * buf
Definition: SnmpRequest.h:21
AggrType aggrType
Definition: snmp_core.h:41
@ MESH_PTBL_INDEX
Definition: cache_snmp.h:236
variable_list * snmp_netDnsFn(variable_list *Var, snint *ErrP)
@ CONF_LOG_FAC
Definition: cache_snmp.h:75
@ IP_HITS
Definition: cache_snmp.h:191
void finalizeConfig() override
Definition: snmp_core.cc:343
@ IP_PENDHIT
Definition: cache_snmp.h:192
@ atNone
Definition: snmp_core.h:29
int name_length
Definition: snmp_vars.h:71
@ CONF_ST_SWLOWM
Definition: cache_snmp.h:92
oid * name
Definition: snmp_vars.h:70
variable_list * snmp_prfProtoFn(variable_list *Var, snint *ErrP)
Definition: snmp_agent.cc:432
@ MESH_CTBL
Definition: cache_snmp.h:229
SQUIDCEXTERN void(* snmplib_debug_hook)(int, char *)
Definition: snmp_core.cc:47
@ CONF_ADMIN
Definition: cache_snmp.h:72
StartListening() result.
@ PERF_SYS_MAXRESSZ
Definition: cache_snmp.h:118
void StartListening(int sock_type, int proto, const Comm::ConnectionPointer &listenConn, FdNoteId, StartListeningCallback &)
@ CONF_ST_SWHIWM
Definition: cache_snmp.h:91
int64_t snint
Definition: cache_snmp.h:14
int size
Definition: ModDevPoll.cc:70
void append(const char *c, int sz) override
Definition: MemBuf.cc:209
Comm::ConnectionPointer conn
opened listening socket
struct variable_list * snmp_var_new(oid *, int)
Definition: snmp_vars.c:109
struct variable_list * variables
Definition: snmp_pdu.h:86
static mib_tree_entry * snmpTreeSiblingEntry(oid entry, snint len, mib_tree_entry *current)
Definition: snmp_core.cc:848
@ PERF_MEDIAN_RHR
Definition: cache_snmp.h:169
int errindex
Definition: snmp_pdu.h:80
mib_tree_entry * mib_tree_head
Definition: snmp_core.cc:36
variable_list * snmp_meshPtblFn(variable_list *Var, snint *ErrP)
Definition: snmp_agent.cc:189
ACLFilledChecklist * Filled(ACLChecklist *checklist)
convenience and safety wrapper for dynamic_cast<ACLFilledChecklist*>
struct snmp_pdu * snmpAgentResponse(struct snmp_pdu *PDU)
Definition: snmp_core.cc:470
const Acl::Answer & fastCheck()
Definition: Checklist.cc:298
@ fdnOutSnmpSocket
Definition: FdNotes.h:22
@ PERF_SYS_MEMUSAGE
Definition: cache_snmp.h:115
struct snmp_session session
Definition: SnmpRequest.h:33
#define SQUIDCEXTERN
Definition: squid.h:21
bool isIPv6() const
Definition: Address.cc:184
Definition: MemBuf.h:23
static oid_ParseFn * snmpTreeGet(oid *Current, snint CurrentLen)
Definition: snmp_core.cc:552
@ MESH_PTBL
Definition: cache_snmp.h:228
@ MESH_PTBL_KEEPAL_S
Definition: cache_snmp.h:249
@ FQDN_NEGHIT
Definition: cache_snmp.h:207
struct snmp_pdu * snmp_pdu_create(int)
Definition: snmp_pdu.c:113
@ PERF_MEDIAN_ICP_QUERY
Definition: cache_snmp.h:166
int command
Definition: snmp_pdu.h:75
#define safe_free(x)
Definition: xalloc.h:73
int reqid
Definition: snmp_pdu.h:78
unsigned short snmp
Definition: SquidConfig.h:148
@ MESH_CTBL_ADDR
Definition: cache_snmp.h:258
@ PERF_MEDIAN_HTTP_NH
Definition: cache_snmp.h:171
@ IP_NEGHIT
Definition: cache_snmp.h:193
@ PERF_PROTOSTAT_AGGR_KBYTES_IN
Definition: cache_snmp.h:151
#define assert(EX)
Definition: assert.h:17
@ NET_IP_CACHE
Definition: cache_snmp.h:180
@ IP_GHBN
Definition: cache_snmp.h:195
@ NET_FQDN_CACHE
Definition: cache_snmp.h:181
SSL Connection
Definition: Session.h:49
#define IPV6_SPECIAL_SPLITSTACK
Definition: tools.h:22
@ CONF_VERSION
Definition: cache_snmp.h:73
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
#define TIME_INDEX
Definition: cache_snmp.h:37
static char identifier[MAXLINE]
@ atSum
Definition: snmp_core.h:29
@ CONF_ST_SWMAXSZ
Definition: cache_snmp.h:90
#define COMM_SELECT_READ
Definition: defines.h:24
Comm::ConnectionPointer snmpIncomingConn
Definition: snmp_core.cc:39
@ MESH_PTBL_STATE
Definition: cache_snmp.h:243
#define SNMP_PDU_GET
Definition: snmp_pdu.h:92
static void snmpConstructReponse(SnmpRequest *rq)
Definition: snmp_core.cc:438
@ PERF_PROTOSTAT_AGGR_ERRORS
Definition: cache_snmp.h:150
@ IP_REQ
Definition: cache_snmp.h:190
variable_list * snmp_netFqdnFn(variable_list *Var, snint *ErrP)
Definition: fqdncache.cc:716
@ PERF_MEDIAN_TIME
Definition: cache_snmp.h:161
@ PERF_PROTOSTAT_AGGR_HTTP_KBYTES_IN
Definition: cache_snmp.h:143
bool isNoAddr() const
Definition: Address.cc:304
#define xfree
@ MESH_PTBL_TYPE
Definition: cache_snmp.h:242
Definition: Pdu.h:23
@ PERF_SYS_PF
Definition: cache_snmp.h:113
void snmp_var_free(struct variable_list *)
Definition: snmp_vars.c:227
@ fdnInSnmpSocket
Definition: FdNotes.h:22
@ FQDN_GHBN
Definition: cache_snmp.h:209
u_char * outbuf
Definition: SnmpRequest.h:22
Ip::Address snmp_outgoing
Definition: SquidConfig.h:239
struct snmp_pdu * PDU
Definition: SnmpRequest.h:30
static void snmpClosePorts()
Definition: snmp_core.cc:321
mib_tree_entry * snmpLookupNodeStr(mib_tree_entry *entry, const char *str)
Definition: snmp_core.cc:902
instance_Fn * instancefunction
Definition: snmp_core.h:35
@ MESH_CTBL_ICPHITBYTES
Definition: cache_snmp.h:266
u_int oid
Definition: asn1.h:42
@ MESH_PTBL_SENT
Definition: cache_snmp.h:244
static void snmpPortOpened(Ipc::StartListeningAnswer &)
Definition: snmp_core.cc:303
@ FQDN_HITS
Definition: cache_snmp.h:205
variable_list * snmp_sysFn(variable_list *Var, snint *ErrP)
Definition: snmp_agent.cc:44
static oid * peer_Inst(oid *name, snint *len, mib_tree_entry *current, oid_ParseFn **Fn)
Definition: snmp_core.cc:736
bool allowed() const
Definition: Acl.h:82
#define SNMP_PDU_GETNEXT
Definition: snmp_pdu.h:93
@ DNS_SERVERS
Definition: cache_snmp.h:218
static mib_tree_entry * snmpTreeEntry(oid entry, snint len, mib_tree_entry *current)
Definition: snmp_core.cc:875
@ PERF_PROTOSTAT_AGGR_CLIENTS
Definition: cache_snmp.h:154
@ PERF_MEDIAN_HTTP_ALL
Definition: cache_snmp.h:162
variable_list * snmp_meshCtblFn(variable_list *Var, snint *ErrP)
Definition: client_db.cc:442
@ FQDN_PENDHIT
Definition: cache_snmp.h:206
@ MESH_CTBL_HTREQ
Definition: cache_snmp.h:259
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
Definition: ModDevPoll.cc:220
char * content()
start of the added data
Definition: MemBuf.h:41
struct SquidConfig::@91 accessList
@ atMin
Definition: snmp_core.h:29
@ CONF_VERSION_ID
Definition: cache_snmp.h:74
@ PERF_SYS_CURUNUSED_FD
Definition: cache_snmp.h:122
auto size() const
the number of currently stored (i.e. added and not removed) cache_peers
Definition: CachePeers.h:33
Definition: snmp_core.h:31
AggrType snmpAggrType(oid *Current, snint CurrentLen)
Definition: snmp_core.cc:583
Ip::Address snmp_incoming
Definition: SquidConfig.h:238
void setAnyAddr()
NOTE: Does NOT clear the Port stored. Only the Address and Type.
Definition: Address.cc:197
@ PERF_PROTOSTAT_AGGR_KBYTES_OUT
Definition: cache_snmp.h:152
variable_list *() oid_ParseFn(variable_list *, snint *)
Definition: snmp_core.h:26
@ PERF_MEDIAN_HTTP_MISS
Definition: cache_snmp.h:163
struct _mib_tree_entry ** leaves
Definition: snmp_core.h:38
#define DBG_IMPORTANT
Definition: Stream.h:38
int len
Definition: snmp_core.h:33
static mib_tree_entry * snmpAddNodeStr(const char *base_str, int o, oid_ParseFn *parsefunction, instance_Fn *instancefunction, AggrType aggrType=atNone)
Definition: snmp_core.cc:973
@ DNS_REP
Definition: cache_snmp.h:217
#define MYNAME
Definition: Stream.h:219
void startShutdown() override
Definition: snmp_core.cc:347
void reset()
Definition: MemBuf.cc:129
void useConfig() override
Definition: snmp_core.cc:344
@ CONF_UNIQNAME
Definition: cache_snmp.h:77
@ PERF_SYS_CPUUSAGE
Definition: cache_snmp.h:117
@ CONF_ST_MMAXSZ
Definition: cache_snmp.h:89
@ MESH_PTBL_ADDR_TYPE
Definition: cache_snmp.h:238
static oid_ParseFn * snmpTreeNext(oid *Current, snint CurrentLen, oid **Next, snint *NextLen)
Definition: snmp_core.cc:606
@ atMax
Definition: snmp_core.h:29
#define INETADDRESSTYPE_IPV6
Definition: snmp_vars.h:94
@ IP_ENT
Definition: cache_snmp.h:189
@ MESH_PTBL_RTT
Definition: cache_snmp.h:247
@ MESH_PTBL_HTTP
Definition: cache_snmp.h:240
@ PERF_PROTO
Definition: cache_snmp.h:106
int comm_udp_recvfrom(int fd, void *buf, size_t len, int flags, Ip::Address &from)
Definition: comm.cc:128
@ MESH_PTBL_NAME
Definition: cache_snmp.h:237
@ SYS_UPTIME
Definition: cache_snmp.h:60
@ PERF_PROTOSTAT_AGGR_HTTP_HITS
Definition: cache_snmp.h:141
#define SNMP_REQUEST_SIZE
Definition: snmp_core.h:23
@ CONF_STORAGE
Definition: cache_snmp.h:76
#define SNMP_ERR_NOSUCHNAME
Definition: snmp_error.h:44
const CachePeers & CurrentCachePeers()
Definition: CachePeers.cc:43
@ FQDN_MISS
Definition: cache_snmp.h:208
oid *() instance_Fn(oid *name, snint *len, mib_tree_entry *current, oid_ParseFn **Fn)
Definition: snmp_core.h:28
variable_list * snmp_prfSysFn(variable_list *Var, snint *ErrP)
Definition: snmp_agent.cc:324
static void snmpInit()
Definition: snmp_core.cc:65
@ PERF_SYS_CURUSED_FD
Definition: cache_snmp.h:124
bool UsingSmp()
Whether there should be more than one worker process running.
Definition: tools.cc:697
@ MESH_CTBL_ADDR_TYPE
Definition: cache_snmp.h:257
@ MESH_CTBL_HTBYTES
Definition: cache_snmp.h:260
@ MESH_PTBL_KEEPAL_R
Definition: cache_snmp.h:250
struct variable_list * next_variable
Definition: snmp_vars.h:69
#define asyncCallbackFun(dbgSection, dbgLevel, function)
AsyncCall for calling back a function.
@ PERF_PROTOSTAT_AGGR
Definition: cache_snmp.h:132
constexpr bool Less(const A a, const B b)
whether integer a is less than integer b, with correct overflow handling
Definition: SquidMath.h:48
int EnableIpv6
Whether IPv6 is supported and type of support.
Definition: tools.h:25
@ PERF_PROTOSTAT_AGGR_HTTP_KBYTES_OUT
Definition: cache_snmp.h:144
void * xrealloc(void *s, size_t sz)
Definition: xalloc.cc:126
@ MESH_CTBL_HTHITBYTES
Definition: cache_snmp.h:262
@ PERF_MEDIAN_HTTP_HIT
Definition: cache_snmp.h:165
DefineRunnerRegistrator(SnmpRr)
void snmpSnmplibDebug(int lvl, char *buf)
Definition: snmp_core.cc:1080
bool snmpCreateOidFromStr(const char *str, oid **name, int *nl)
Definition: snmp_core.cc:944
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
void addr2oid(Ip::Address &addr, oid *Dest)
Definition: snmp_core.cc:1092
@ MESH_CTBL_ICPBYTES
Definition: cache_snmp.h:264
@ MESH_PTBL_ICP
Definition: cache_snmp.h:241
u_char * community
Definition: SnmpRequest.h:31
#define SNMP_ERR_NOERROR
Definition: snmp_error.h:42
int snmp_coexist_V2toV1(struct snmp_pdu *)
Definition: coexistance.c:108
static oid * snmpCreateOid(int length,...)
Definition: snmp_core.cc:1043
class SquidConfig Config
Definition: SquidConfig.cc:12
int unsigned int
Definition: stub_fd.cc:19
static void Start(const Pointer &job)
Definition: AsyncJob.cc:37
int errstat
Definition: snmp_pdu.h:79
@ PERF_SYS_NUMR
Definition: cache_snmp.h:114
@ PERF_PROTOSTAT_AGGR_ICP_RKB
Definition: cache_snmp.h:148

 

Introduction

Documentation

Support

Miscellaneous