2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 49 SNMP support */
12 #include "acl/FilledChecklist.h"
13 #include "base/AsyncCallbacks.h"
14 #include "base/CbcPointer.h"
15 #include "CachePeer.h"
16 #include "CachePeers.h"
17 #include "client_db.h"
19 #include "comm/Connection.h"
20 #include "comm/Loops.h"
22 #include "ip/Address.h"
24 #include "ipc/StartListening.h"
25 #include "snmp/Forwarder.h"
26 #include "snmp_agent.h"
27 #include "snmp_core.h"
28 #include "SnmpRequest.h"
29 #include "SquidConfig.h"
30 #include "SquidMath.h"
33 static void snmpPortOpened(Ipc::StartListeningAnswer
&);
35 mib_tree_entry
*mib_tree_head
;
36 mib_tree_entry
*mib_tree_last
;
38 Comm::ConnectionPointer snmpIncomingConn
;
39 Comm::ConnectionPointer snmpOutgoingConn
;
41 static mib_tree_entry
* snmpAddNodeStr(const char *base_str
, int o
, oid_ParseFn
* parsefunction
, instance_Fn
* instancefunction
, AggrType aggrType
= atNone
);
42 static mib_tree_entry
*snmpAddNode(oid
* name
, int len
, oid_ParseFn
* parsefunction
, instance_Fn
* instancefunction
, AggrType aggrType
, int children
,...);
43 static oid
*snmpCreateOid(int length
,...);
44 mib_tree_entry
* snmpLookupNodeStr(mib_tree_entry
*entry
, const char *str
);
45 bool snmpCreateOidFromStr(const char *str
, oid
**name
, int *nl
);
46 SQUIDCEXTERN
void (*snmplib_debug_hook
) (int, char *);
47 static oid
*static_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
);
48 static oid
*time_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
);
49 static oid
*peer_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
);
50 static oid
*client_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
);
51 static void snmpDecodePacket(SnmpRequest
* rq
);
52 static void snmpConstructReponse(SnmpRequest
* rq
);
54 static oid_ParseFn
*snmpTreeNext(oid
* Current
, snint CurrentLen
, oid
** Next
, snint
* NextLen
);
55 static oid_ParseFn
*snmpTreeGet(oid
* Current
, snint CurrentLen
);
56 static mib_tree_entry
*snmpTreeEntry(oid entry
, snint len
, mib_tree_entry
* current
);
57 static mib_tree_entry
*snmpTreeSiblingEntry(oid entry
, snint len
, mib_tree_entry
* current
);
58 extern "C" void snmpSnmplibDebug(int lvl
, char *buf
);
61 * The functions used during startup:
68 * Turns the MIB into a Tree structure. Called during the startup process.
73 debugs(49, 5, "snmpInit: Building SNMP mib tree structure");
75 snmplib_debug_hook
= snmpSnmplibDebug
;
78 * This following bit of evil is to get the final node in the "squid" mib
79 * without having a "search" function. A search function should be written
80 * to make this and the other code much less evil.
82 mib_tree_head
= snmpAddNode(snmpCreateOid(1, 1), 1, nullptr, nullptr, atNone
, 0);
84 assert(mib_tree_head
);
85 debugs(49, 5, "snmpInit: root is " << mib_tree_head
);
86 snmpAddNodeStr("1", 3, nullptr, nullptr);
88 snmpAddNodeStr("1.3", 6, nullptr, nullptr);
90 snmpAddNodeStr("1.3.6", 1, nullptr, nullptr);
91 snmpAddNodeStr("1.3.6.1", 4, nullptr, nullptr);
92 snmpAddNodeStr("1.3.6.1.4", 1, nullptr, nullptr);
93 snmpAddNodeStr("1.3.6.1.4.1", 3495, nullptr, nullptr);
94 mib_tree_entry
*m2
= snmpAddNodeStr("1.3.6.1.4.1.3495", 1, nullptr, nullptr);
96 mib_tree_entry
*n
= snmpLookupNodeStr(nullptr, "1.3.6.1.4.1.3495.1");
99 /* SQ_SYS - 1.3.6.1.4.1.3495.1.1 */
100 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 1, nullptr, nullptr);
101 snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSVMSIZ
, snmp_sysFn
, static_Inst
, atSum
);
102 snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSSTOR
, snmp_sysFn
, static_Inst
, atSum
);
103 snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYS_UPTIME
, snmp_sysFn
, static_Inst
, atMax
);
105 /* SQ_CONF - 1.3.6.1.4.1.3495.1.2 */
106 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 2, nullptr, nullptr);
107 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_ADMIN
, snmp_confFn
, static_Inst
);
108 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_VERSION
, snmp_confFn
, static_Inst
);
109 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_VERSION_ID
, snmp_confFn
, static_Inst
);
110 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_LOG_FAC
, snmp_confFn
, static_Inst
);
112 /* SQ_CONF + CONF_STORAGE - 1.3.6.1.4.1.3495.1.5 */
113 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_STORAGE
, nullptr, nullptr);
114 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_MMAXSZ
, snmp_confFn
, static_Inst
, atSum
);
115 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWMAXSZ
, snmp_confFn
, static_Inst
, atSum
);
116 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWHIWM
, snmp_confFn
, static_Inst
, atMin
);
117 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWLOWM
, snmp_confFn
, static_Inst
, atMin
);
119 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_UNIQNAME
, snmp_confFn
, static_Inst
);
121 /* SQ_PRF - 1.3.6.1.4.1.3495.1.3 */
122 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 3, nullptr, nullptr); /* SQ_PRF */
124 /* PERF_SYS - 1.3.6.1.4.1.3495.1.3.1 */
125 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3", PERF_SYS
, nullptr, nullptr);
126 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_PF
, snmp_prfSysFn
, static_Inst
, atSum
);
127 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMR
, snmp_prfSysFn
, static_Inst
, atSum
);
128 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MEMUSAGE
, snmp_prfSysFn
, static_Inst
, atSum
);
129 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUTIME
, snmp_prfSysFn
, static_Inst
, atSum
);
130 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUUSAGE
, snmp_prfSysFn
, static_Inst
, atSum
);
131 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MAXRESSZ
, snmp_prfSysFn
, static_Inst
, atSum
);
132 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMOBJCNT
, snmp_prfSysFn
, static_Inst
, atSum
);
135 The meaning of LRU is "oldest timestamped object in cache, if LRU algorithm is
137 What this SMP support needs to do is aggregate via a special filter equivalent to
138 min() to retain the semantic oldest-object meaning. A special one is needed that
139 works as unsigned and ignores '0' values.
141 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURLRUEXP
, snmp_prfSysFn
, static_Inst
);
142 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUNLREQ
, snmp_prfSysFn
, static_Inst
, atSum
);
143 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUNUSED_FD
, snmp_prfSysFn
, static_Inst
, atSum
);
144 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURRESERVED_FD
, snmp_prfSysFn
, static_Inst
, atSum
);
145 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUSED_FD
, snmp_prfSysFn
, static_Inst
, atSum
);
146 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURMAX_FD
, snmp_prfSysFn
, static_Inst
, atMax
);
148 /* PERF_PROTO - 1.3.6.1.4.1.3495.1.3.2 */
149 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3", PERF_PROTO
, nullptr, nullptr);
150 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2", PERF_PROTOSTAT_AGGR
, nullptr, nullptr);
151 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_REQ
, snmp_prfProtoFn
, static_Inst
, atSum
);
152 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_HITS
, snmp_prfProtoFn
, static_Inst
, atSum
);
153 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_ERRORS
, snmp_prfProtoFn
, static_Inst
, atSum
);
154 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_KBYTES_IN
, snmp_prfProtoFn
, static_Inst
, atSum
);
155 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_KBYTES_OUT
, snmp_prfProtoFn
, static_Inst
, atSum
);
156 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_S
, snmp_prfProtoFn
, static_Inst
, atSum
);
157 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_R
, snmp_prfProtoFn
, static_Inst
, atSum
);
158 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_SKB
, snmp_prfProtoFn
, static_Inst
, atSum
);
159 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_RKB
, snmp_prfProtoFn
, static_Inst
, atSum
);
160 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_REQ
, snmp_prfProtoFn
, static_Inst
, atSum
);
161 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ERRORS
, snmp_prfProtoFn
, static_Inst
, atSum
);
162 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_KBYTES_IN
, snmp_prfProtoFn
, static_Inst
, atSum
);
163 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_KBYTES_OUT
, snmp_prfProtoFn
, static_Inst
, atSum
);
164 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_CURSWAP
, snmp_prfProtoFn
, static_Inst
, atSum
);
165 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_CLIENTS
, snmp_prfProtoFn
, static_Inst
, atSum
);
167 /* Note this is time-series rather than 'static' */
168 /* cacheMedianSvcTable */
169 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2", PERF_PROTOSTAT_MEDIAN
, nullptr, nullptr);
171 /* cacheMedianSvcEntry */
172 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2", 1, nullptr, nullptr);
173 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_TIME
, snmp_prfProtoFn
, time_Inst
, atAverage
);
174 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_ALL
, snmp_prfProtoFn
, time_Inst
, atAverage
);
175 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_MISS
, snmp_prfProtoFn
, time_Inst
, atAverage
);
176 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NM
, snmp_prfProtoFn
, time_Inst
, atAverage
);
177 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_HIT
, snmp_prfProtoFn
, time_Inst
, atAverage
);
178 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_QUERY
, snmp_prfProtoFn
, time_Inst
, atAverage
);
179 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_REPLY
, snmp_prfProtoFn
, time_Inst
, atAverage
);
180 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_DNS
, snmp_prfProtoFn
, time_Inst
, atAverage
);
181 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_RHR
, snmp_prfProtoFn
, time_Inst
, atAverage
);
182 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_BHR
, snmp_prfProtoFn
, time_Inst
, atAverage
);
183 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NH
, snmp_prfProtoFn
, time_Inst
, atAverage
);
185 /* SQ_NET - 1.3.6.1.4.1.3495.1.4 */
186 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 4, nullptr, nullptr);
188 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_IP_CACHE
, nullptr, nullptr);
189 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_ENT
, snmp_netIpFn
, static_Inst
, atSum
);
190 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_REQ
, snmp_netIpFn
, static_Inst
, atSum
);
191 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_HITS
, snmp_netIpFn
, static_Inst
, atSum
);
192 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_PENDHIT
, snmp_netIpFn
, static_Inst
, atSum
);
193 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_NEGHIT
, snmp_netIpFn
, static_Inst
, atSum
);
194 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_MISS
, snmp_netIpFn
, static_Inst
, atSum
);
195 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_GHBN
, snmp_netIpFn
, static_Inst
, atSum
);
196 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_LOC
, snmp_netIpFn
, static_Inst
, atSum
);
198 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_FQDN_CACHE
, nullptr, nullptr);
199 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_ENT
, snmp_netFqdnFn
, static_Inst
, atSum
);
200 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_REQ
, snmp_netFqdnFn
, static_Inst
, atSum
);
201 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_HITS
, snmp_netFqdnFn
, static_Inst
, atSum
);
202 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_PENDHIT
, snmp_netFqdnFn
, static_Inst
, atSum
);
203 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_NEGHIT
, snmp_netFqdnFn
, static_Inst
, atSum
);
204 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_MISS
, snmp_netFqdnFn
, static_Inst
, atSum
);
205 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_GHBN
, snmp_netFqdnFn
, static_Inst
, atSum
);
207 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_DNS_CACHE
, nullptr, nullptr);
208 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REQ
, snmp_netDnsFn
, static_Inst
, atSum
);
209 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REP
, snmp_netDnsFn
, static_Inst
, atSum
);
210 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_SERVERS
, snmp_netDnsFn
, static_Inst
, atSum
);
212 /* SQ_MESH - 1.3.6.1.4.1.3495.1.5 */
213 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 5, nullptr, nullptr);
215 /* cachePeerTable - 1.3.6.1.4.1.3495.1.5.1 */
216 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5", MESH_PTBL
, nullptr, nullptr);
218 /* CachePeerEntry (version 3) - 1.3.6.1.4.1.3495.1.5.1.3 */
219 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1", 3, nullptr, nullptr);
220 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_INDEX
, snmp_meshPtblFn
, peer_Inst
);
221 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_NAME
, snmp_meshPtblFn
, peer_Inst
);
222 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ADDR_TYPE
, snmp_meshPtblFn
, peer_Inst
);
223 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ADDR
, snmp_meshPtblFn
, peer_Inst
);
224 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_HTTP
, snmp_meshPtblFn
, peer_Inst
);
225 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ICP
, snmp_meshPtblFn
, peer_Inst
);
226 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_TYPE
, snmp_meshPtblFn
, peer_Inst
);
227 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_STATE
, snmp_meshPtblFn
, peer_Inst
);
228 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_SENT
, snmp_meshPtblFn
, peer_Inst
);
229 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_PACKED
, snmp_meshPtblFn
, peer_Inst
);
230 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_FETCHES
, snmp_meshPtblFn
, peer_Inst
);
231 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_RTT
, snmp_meshPtblFn
, peer_Inst
);
232 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_IGN
, snmp_meshPtblFn
, peer_Inst
);
233 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_KEEPAL_S
, snmp_meshPtblFn
, peer_Inst
);
234 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_KEEPAL_R
, snmp_meshPtblFn
, peer_Inst
);
236 /* cacheClientTable - 1.3.6.1.4.1.3495.1.5.2 */
237 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5", MESH_CTBL
, nullptr, nullptr);
239 /* BUG 2811: we NEED to create a reliable index for the client DB and make version 3 of the table. */
240 /* for now we have version 2 table with OID capable of mixed IPv4 / IPv6 clients and upgraded address text format. */
242 /* cacheClientEntry - 1.3.6.1.4.1.3495.1.5.2.2 */
243 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2", 2, nullptr, nullptr);
244 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ADDR_TYPE
, snmp_meshCtblFn
, client_Inst
);
245 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ADDR
, snmp_meshCtblFn
, client_Inst
);
246 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTREQ
, snmp_meshCtblFn
, client_Inst
);
247 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTBYTES
, snmp_meshCtblFn
, client_Inst
);
248 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTHITS
, snmp_meshCtblFn
, client_Inst
);
249 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTHITBYTES
, snmp_meshCtblFn
, client_Inst
);
250 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPREQ
, snmp_meshCtblFn
, client_Inst
);
251 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPBYTES
, snmp_meshCtblFn
, client_Inst
);
252 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPHITS
, snmp_meshCtblFn
, client_Inst
);
253 mib_tree_last
= snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPHITBYTES
, snmp_meshCtblFn
, client_Inst
);
255 debugs(49, 9, "snmpInit: Completed SNMP mib tree structure");
261 debugs(49, 5, "snmpConnectionOpen: Called");
263 if (Config
.Port
.snmp
<= 0)
266 snmpIncomingConn
= new Comm::Connection
;
267 snmpIncomingConn
->local
= Config
.Addrs
.snmp_incoming
;
268 snmpIncomingConn
->local
.port(Config
.Port
.snmp
);
270 if (!Ip::EnableIpv6
&& !snmpIncomingConn
->local
.setIPv4()) {
271 debugs(49, DBG_CRITICAL
, "ERROR: IPv6 is disabled. " << snmpIncomingConn
->local
<< " is not an IPv4 address.");
272 fatal("SNMP port cannot be opened.");
274 /* split-stack for now requires IPv4-only SNMP */
275 if (Ip::EnableIpv6
&IPV6_SPECIAL_SPLITSTACK
&& snmpIncomingConn
->local
.isAnyAddr()) {
276 snmpIncomingConn
->local
.setIPv4();
279 auto call
= asyncCallbackFun(49, 2, snmpPortOpened
);
280 Ipc::StartListening(SOCK_DGRAM
, IPPROTO_UDP
, snmpIncomingConn
, Ipc::fdnInSnmpSocket
, call
);
282 if (!Config
.Addrs
.snmp_outgoing
.isNoAddr()) {
283 snmpOutgoingConn
= new Comm::Connection
;
284 snmpOutgoingConn
->local
= Config
.Addrs
.snmp_outgoing
;
285 snmpOutgoingConn
->local
.port(Config
.Port
.snmp
);
287 if (!Ip::EnableIpv6
&& !snmpOutgoingConn
->local
.setIPv4()) {
288 debugs(49, DBG_CRITICAL
, "ERROR: IPv6 is disabled. " << snmpOutgoingConn
->local
<< " is not an IPv4 address.");
289 fatal("SNMP port cannot be opened.");
291 /* split-stack for now requires IPv4-only SNMP */
292 if (Ip::EnableIpv6
&IPV6_SPECIAL_SPLITSTACK
&& snmpOutgoingConn
->local
.isAnyAddr()) {
293 snmpOutgoingConn
->local
.setIPv4();
295 // TODO: Add/use snmpOutgoingPortOpened() instead of snmpPortOpened().
296 auto c
= asyncCallbackFun(49, 2, snmpPortOpened
);
297 Ipc::StartListening(SOCK_DGRAM
, IPPROTO_UDP
, snmpOutgoingConn
, Ipc::fdnOutSnmpSocket
, c
);
299 snmpOutgoingConn
= snmpIncomingConn
;
300 debugs(1, DBG_IMPORTANT
, "Sending SNMP messages from " << snmpOutgoingConn
->local
);
305 snmpPortOpened(Ipc::StartListeningAnswer
&answer
)
307 const auto &conn
= answer
.conn
;
309 if (!Comm::IsConnOpen(conn
))
310 fatalf("Cannot open SNMP %s Port",(conn
->fd
== snmpIncomingConn
->fd
?"receiving":"sending"));
312 Comm::SetSelect(conn
->fd
, COMM_SELECT_READ
, snmpHandleUdp
, nullptr, 0);
314 if (conn
->fd
== snmpIncomingConn
->fd
)
315 debugs(1, DBG_IMPORTANT
, "Accepting SNMP messages on " << snmpIncomingConn
->local
);
316 else if (conn
->fd
== snmpOutgoingConn
->fd
)
317 debugs(1, DBG_IMPORTANT
, "Sending SNMP messages from " << snmpOutgoingConn
->local
);
319 fatalf("Lost SNMP port (%d) on FD %d", (int)conn
->local
.port(), conn
->fd
);
325 if (Comm::IsConnOpen(snmpIncomingConn
)) {
326 debugs(49, DBG_IMPORTANT
, "Closing SNMP receiving port " << snmpIncomingConn
->local
);
327 snmpIncomingConn
->close();
329 snmpIncomingConn
= nullptr;
331 if (Comm::IsConnOpen(snmpOutgoingConn
) && snmpIncomingConn
!= snmpOutgoingConn
) {
332 // Perform OUT port closure so as not to step on IN port when sharing a conn.
333 debugs(49, DBG_IMPORTANT
, "Closing SNMP sending port " << snmpOutgoingConn
->local
);
334 snmpOutgoingConn
->close();
336 snmpOutgoingConn
= nullptr;
340 * Functions for handling the requests.
344 * Accept the UDP packet
347 snmpHandleUdp(int sock
, void *)
349 static char buf
[SNMP_REQUEST_SIZE
];
351 SnmpRequest
*snmp_rq
;
354 debugs(49, 5, "snmpHandleUdp: Called.");
356 Comm::SetSelect(sock
, COMM_SELECT_READ
, snmpHandleUdp
, nullptr, 0);
358 memset(buf
, '\0', sizeof(buf
));
360 len
= comm_udp_recvfrom(sock
, buf
, sizeof(buf
)-1, 0, from
);
363 debugs(49, 3, "snmpHandleUdp: FD " << sock
<< ": received " << len
<< " bytes from " << from
<< ".");
365 snmp_rq
= (SnmpRequest
*)xcalloc(1, sizeof(SnmpRequest
));
366 snmp_rq
->buf
= (u_char
*) buf
;
368 snmp_rq
->sock
= sock
;
369 snmp_rq
->outbuf
= (unsigned char *)xmalloc(snmp_rq
->outlen
= SNMP_REQUEST_SIZE
);
370 snmp_rq
->from
= from
;
371 snmpDecodePacket(snmp_rq
);
372 xfree(snmp_rq
->outbuf
);
376 debugs(49, DBG_IMPORTANT
, "snmpHandleUdp: FD " << sock
<< " recvfrom: " << xstrerr(xerrno
));
381 * Turn SNMP packet into a PDU, check available ACL's
384 snmpDecodePacket(SnmpRequest
* rq
)
386 struct snmp_pdu
*PDU
;
388 u_char
*buf
= rq
->buf
;
391 if (!Config
.accessList
.snmp
) {
392 debugs(49, DBG_IMPORTANT
, "WARNING: snmp_access not configured. agent query DENIED from : " << rq
->from
);
396 debugs(49, 5, "Called.");
397 PDU
= snmp_pdu_create(0);
398 /* Always answer on SNMPv1 */
399 rq
->session
.Version
= SNMP_VERSION_1
;
400 Community
= snmp_parse(&rq
->session
, PDU
, buf
, len
);
402 /* Check if we have explicit permission to access SNMP data.
403 * default (set above) is to deny all */
405 ACLFilledChecklist
checklist(Config
.accessList
.snmp
, nullptr);
406 checklist
.src_addr
= rq
->from
;
407 checklist
.snmp_community
= (char *) Community
;
409 if (checklist
.fastCheck().allowed() && (snmp_coexist_V2toV1(PDU
))) {
410 rq
->community
= Community
;
412 debugs(49, 5, "snmpAgentParse: reqid=[" << PDU
->reqid
<< "]");
413 snmpConstructReponse(rq
);
415 debugs(49, DBG_IMPORTANT
, "WARNING: SNMP agent query DENIED from : " << rq
->from
);
421 debugs(49, DBG_IMPORTANT
, "WARNING: Failed SNMP agent query from : " << rq
->from
);
427 * Packet OK, ACL Check OK, Create response.
430 snmpConstructReponse(SnmpRequest
* rq
)
433 struct snmp_pdu
*RespPDU
;
435 debugs(49, 5, "snmpConstructReponse: Called.");
437 if (UsingSmp() && IamWorkerProcess()) {
438 AsyncJob::Start(new Snmp::Forwarder(static_cast<Snmp::Pdu
&>(*rq
->PDU
),
439 static_cast<Snmp::Session
&>(rq
->session
), rq
->sock
, rq
->from
));
440 snmp_free_pdu(rq
->PDU
);
444 RespPDU
= snmpAgentResponse(rq
->PDU
);
445 snmp_free_pdu(rq
->PDU
);
447 if (RespPDU
!= nullptr) {
448 snmp_build(&rq
->session
, RespPDU
, rq
->outbuf
, &rq
->outlen
);
449 comm_udp_sendto(rq
->sock
, rq
->from
, rq
->outbuf
, rq
->outlen
);
450 snmp_free_pdu(RespPDU
);
455 * Decide how to respond to the request, construct a response and
456 * return the response to the requester.
460 snmpAgentResponse(struct snmp_pdu
*PDU
) {
462 struct snmp_pdu
*Answer
= nullptr;
464 debugs(49, 5, "snmpAgentResponse: Called.");
466 if ((Answer
= snmp_pdu_create(SNMP_PDU_RESPONSE
))) {
467 Answer
->reqid
= PDU
->reqid
;
468 Answer
->errindex
= 0;
470 if (PDU
->command
== SNMP_PDU_GET
|| PDU
->command
== SNMP_PDU_GETNEXT
) {
472 int get_next
= (PDU
->command
== SNMP_PDU_GETNEXT
);
473 variable_list
*VarPtr_
;
474 variable_list
**RespVars
= &(Answer
->variables
);
475 oid_ParseFn
*ParseFn
;
477 /* Loop through all variables */
479 for (VarPtr_
= PDU
->variables
; VarPtr_
; VarPtr_
= VarPtr_
->next_variable
) {
480 variable_list
*VarPtr
= VarPtr_
;
481 variable_list
*VarNew
= nullptr;
482 oid
*NextOidName
= nullptr;
483 snint NextOidNameLen
= 0;
488 ParseFn
= snmpTreeNext(VarPtr
->name
, VarPtr
->name_length
, &NextOidName
, &NextOidNameLen
);
490 ParseFn
= snmpTreeGet(VarPtr
->name
, VarPtr
->name_length
);
492 if (ParseFn
== nullptr) {
493 Answer
->errstat
= SNMP_ERR_NOSUCHNAME
;
494 debugs(49, 5, "snmpAgentResponse: No such oid. ");
497 VarPtr
= snmp_var_new(NextOidName
, NextOidNameLen
);
501 int * errstatTmp
= &(Answer
->errstat
);
503 VarNew
= (*ParseFn
) (VarPtr
, (snint
*) errstatTmp
);
506 snmp_var_free(VarPtr
);
509 if ((Answer
->errstat
!= SNMP_ERR_NOERROR
) || (VarNew
== nullptr)) {
510 Answer
->errindex
= index
;
511 debugs(49, 5, "snmpAgentResponse: error.");
514 snmp_var_free(VarNew
);
516 while ((VarPtr
= Answer
->variables
) != nullptr) {
517 Answer
->variables
= VarPtr
->next_variable
;
518 snmp_var_free(VarPtr
);
521 /* Steal the original PDU list of variables for the error response */
522 Answer
->variables
= PDU
->variables
;
524 PDU
->variables
= nullptr;
529 /* No error. Insert this var at the end, and move on to the next.
533 RespVars
= &(VarNew
->next_variable
);
542 snmpTreeGet(oid
* Current
, snint CurrentLen
)
544 oid_ParseFn
*Fn
= nullptr;
545 mib_tree_entry
*mibTreeEntry
= nullptr;
548 debugs(49, 5, "snmpTreeGet: Called");
551 debugs(49, 6, "snmpTreeGet: Current : " << snmpDebugOid(Current
, CurrentLen
, tmp
) );
553 mibTreeEntry
= mib_tree_head
;
555 if (Current
[count
] == mibTreeEntry
->name
[count
]) {
558 while ((mibTreeEntry
) && (count
< CurrentLen
) && (!mibTreeEntry
->parsefunction
)) {
559 mibTreeEntry
= snmpTreeEntry(Current
[count
], count
, mibTreeEntry
);
564 if (mibTreeEntry
&& mibTreeEntry
->parsefunction
)
565 Fn
= mibTreeEntry
->parsefunction
;
567 debugs(49, 5, "snmpTreeGet: return");
573 snmpAggrType(oid
* Current
, snint CurrentLen
)
575 debugs(49, 5, MYNAME
);
577 mib_tree_entry
* mibTreeEntry
= mib_tree_head
;
578 AggrType type
= atNone
;
581 if (Current
[count
] == mibTreeEntry
->name
[count
]) {
584 while (mibTreeEntry
!= nullptr && count
< CurrentLen
) {
585 mibTreeEntry
= snmpTreeEntry(Current
[count
], count
, mibTreeEntry
);
586 if (mibTreeEntry
!= nullptr)
587 type
= mibTreeEntry
->aggrType
;
596 snmpTreeNext(oid
* Current
, snint CurrentLen
, oid
** Next
, snint
* NextLen
)
598 oid_ParseFn
*Fn
= nullptr;
601 debugs(49, 5, "snmpTreeNext: Called");
604 debugs(49, 6, "snmpTreeNext: Current : " << snmpDebugOid(Current
, CurrentLen
, tmp
));
606 mib_tree_entry
*mibTreeEntry
= mib_tree_head
;
608 if (mibTreeEntry
&& Current
[count
] == mibTreeEntry
->name
[count
]) {
611 while ((mibTreeEntry
) && (count
< CurrentLen
) && (!mibTreeEntry
->parsefunction
)) {
612 mib_tree_entry
*nextmibTreeEntry
= snmpTreeEntry(Current
[count
], count
, mibTreeEntry
);
614 if (!nextmibTreeEntry
)
617 mibTreeEntry
= nextmibTreeEntry
;
621 debugs(49, 5, "snmpTreeNext: Recursed down to requested object");
626 if (mibTreeEntry
== mib_tree_last
)
629 if ((mibTreeEntry
) && (mibTreeEntry
->parsefunction
)) {
630 *NextLen
= CurrentLen
;
631 *Next
= (*mibTreeEntry
->instancefunction
) (Current
, NextLen
, mibTreeEntry
, &Fn
);
633 debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next
, *NextLen
, tmp
));
638 if ((mibTreeEntry
) && (mibTreeEntry
->parsefunction
)) {
640 mib_tree_entry
*nextoid
= snmpTreeSiblingEntry(Current
[count
], count
, mibTreeEntry
->parent
);
642 debugs(49, 5, "snmpTreeNext: Next OID found for sibling" << nextoid
);
643 mibTreeEntry
= nextoid
;
646 debugs(49, 5, "snmpTreeNext: Attempting to recurse up for next object");
651 if (mibTreeEntry
->parent
->parent
) {
652 nextoid
= mibTreeEntry
->parent
;
653 mibTreeEntry
= snmpTreeEntry(Current
[count
] + 1, count
, nextoid
->parent
);
656 mibTreeEntry
= nextoid
;
660 nextoid
= mibTreeEntry
;
661 mibTreeEntry
= nullptr;
666 while ((mibTreeEntry
) && (!mibTreeEntry
->parsefunction
)) {
667 mibTreeEntry
= mibTreeEntry
->leaves
[0];
671 *NextLen
= mibTreeEntry
->len
;
672 *Next
= (*mibTreeEntry
->instancefunction
) (mibTreeEntry
->name
, NextLen
, mibTreeEntry
, &Fn
);
676 debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next
, *NextLen
, tmp
));
683 static_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
)
685 oid
*instance
= nullptr;
686 if (*len
<= current
->len
) {
687 instance
= (oid
*)xmalloc(sizeof(*name
) * (*len
+ 1));
688 memcpy(instance
, name
, sizeof(*name
) * (*len
));
692 *Fn
= current
->parsefunction
;
697 time_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
)
699 oid
*instance
= nullptr;
700 int identifier
= 0, loop
= 0;
701 int index
[TIME_INDEX_LEN
] = {TIME_INDEX
};
703 if (*len
<= current
->len
) {
704 instance
= (oid
*)xmalloc(sizeof(*name
) * (*len
+ 1));
705 memcpy(instance
, name
, sizeof(*name
) * (*len
));
706 instance
[*len
] = *index
;
709 identifier
= name
[*len
- 1];
711 while ((loop
< TIME_INDEX_LEN
) && (identifier
!= index
[loop
]))
714 if (loop
< (TIME_INDEX_LEN
- 1)) {
715 instance
= (oid
*)xmalloc(sizeof(*name
) * (*len
));
716 memcpy(instance
, name
, sizeof(*name
) * (*len
));
717 instance
[*len
- 1] = index
[++loop
];
721 *Fn
= current
->parsefunction
;
726 peer_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
)
728 oid
*instance
= nullptr;
729 const auto peersAvailable
= CurrentCachePeers().size();
731 if (!peersAvailable
) {
732 debugs(49, 6, "snmp peer_Inst: No Peers.");
733 current
= current
->parent
->parent
->parent
->leaves
[1];
734 while ((current
) && (!current
->parsefunction
))
735 current
= current
->leaves
[0];
740 instance
= client_Inst(current
->name
, len
, current
, Fn
);
741 } else if (*len
<= current
->len
) {
742 debugs(49, 6, "snmp peer_Inst: *len <= current->len ???");
743 instance
= (oid
*)xmalloc(sizeof(*name
) * ( *len
+ 1));
744 memcpy(instance
, name
, sizeof(*name
) * (*len
));
748 int no
= name
[current
->len
] ;
750 // Note: This works because the Config.peers keeps its index according to its position.
751 for (i
= 0; Less(i
, peersAvailable
) && Less(i
, no
); ++i
);
753 if (Less(i
, peersAvailable
)) {
754 debugs(49, 6, "snmp peer_Inst: Encode peer #" << i
);
755 instance
= (oid
*)xmalloc(sizeof(*name
) * (current
->len
+ 1 ));
756 memcpy(instance
, name
, (sizeof(*name
) * current
->len
));
757 instance
[current
->len
] = no
+ 1 ; // i.e. the next index on cache_peeer table.
759 debugs(49, 6, "snmp peer_Inst: We have " << i
<< " peers. Can't find #" << no
);
763 *Fn
= current
->parsefunction
;
768 client_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
)
770 oid
*instance
= nullptr;
776 if (*len
<= current
->len
) {
777 aux
= client_entry(nullptr);
784 size
= sizeof(in_addr
);
786 size
= sizeof(in6_addr
);
788 debugs(49, 6, "len" << *len
<< ", current-len" << current
->len
<< ", addr=" << laddr
<< ", size=" << size
);
790 instance
= (oid
*)xmalloc(sizeof(*name
) * (*len
+ size
));
791 memcpy(instance
, name
, (sizeof(*name
) * (*len
)));
793 if ( !laddr
.isAnyAddr() ) {
794 addr2oid(laddr
, &instance
[ *len
]); // the addr
798 int shift
= *len
- current
->len
; // i.e 4 or 16
799 oid2addr(&name
[*len
- shift
], laddr
,shift
);
800 aux
= client_entry(&laddr
);
806 if (!laddr
.isAnyAddr()) {
808 newshift
= sizeof(in_addr
);
810 newshift
= sizeof(in6_addr
);
812 debugs(49, 6, "len" << *len
<< ", current-len" << current
->len
<< ", addr=" << laddr
<< ", newshift=" << newshift
);
814 instance
= (oid
*)xmalloc(sizeof(*name
) * (current
->len
+ newshift
));
815 memcpy(instance
, name
, (sizeof(*name
) * (current
->len
)));
816 addr2oid(laddr
, &instance
[current
->len
]); // the addr.
817 *len
= current
->len
+ newshift
;
821 *Fn
= current
->parsefunction
;
830 * Tree utility functions.
834 * Returns a sibling object for the requested child object or NULL
835 * if it does not exit
837 static mib_tree_entry
*
838 snmpTreeSiblingEntry(oid entry
, snint len
, mib_tree_entry
* current
)
840 mib_tree_entry
*next
= nullptr;
843 while ((!next
) && (count
< current
->children
)) {
844 if (current
->leaves
[count
]->name
[len
] == entry
) {
845 next
= current
->leaves
[count
];
851 /* Exactly the sibling on right */
852 if (count
< current
->children
) {
853 next
= current
->leaves
[count
];
862 * Returns the requested child object or NULL if it does not exist
864 static mib_tree_entry
*
865 snmpTreeEntry(oid entry
, snint len
, mib_tree_entry
* current
)
867 mib_tree_entry
*next
= nullptr;
870 while ((!next
) && current
&& (count
< current
->children
)) {
871 if (current
->leaves
[count
]->name
[len
] == entry
) {
872 next
= current
->leaves
[count
];
882 snmpAddNodeChild(mib_tree_entry
*entry
, mib_tree_entry
*child
)
884 debugs(49, 5, "snmpAddNodeChild: assigning " << child
<< " to parent " << entry
);
885 entry
->leaves
= (mib_tree_entry
**)xrealloc(entry
->leaves
, sizeof(mib_tree_entry
*) * (entry
->children
+ 1));
886 entry
->leaves
[entry
->children
] = child
;
887 entry
->leaves
[entry
->children
]->parent
= entry
;
892 snmpLookupNodeStr(mib_tree_entry
*root
, const char *str
)
903 if (! snmpCreateOidFromStr(str
, &name
, &namelen
))
906 /* I wish there were some kind of sensible existing tree traversal
907 * routine to use. I'll worry about that later */
910 return e
; /* XXX it should only be this? */
914 while (r
< namelen
) {
916 /* Find the child node which matches this */
917 for (i
= 0; i
< e
->children
&& e
->leaves
[i
]->name
[r
] != name
[r
]; ++i
) ; // seek-loop
919 /* Are we pointing to that node? */
920 if (i
>= e
->children
)
922 assert(e
->leaves
[i
]->name
[r
] == name
[r
]);
924 /* Skip to that node! */
934 snmpCreateOidFromStr(const char *str
, oid
**name
, int *nl
)
936 char const *delim
= ".";
942 /* Parse the OID string into oid bits */
943 while (size_t len
= strcspn(s
, delim
)) {
944 *name
= (oid
*)xrealloc(*name
, sizeof(oid
) * ((*nl
) + 1));
945 (*name
)[*nl
] = atoi(s
); // stops at the '.' delimiter
947 // exit with true when the last octet has been parsed
953 // if we aborted before the lst octet was found, return false.
959 * Create an entry. Return a pointer to the newly created node, or NULL
962 static mib_tree_entry
*
963 snmpAddNodeStr(const char *base_str
, int o
, oid_ParseFn
* parsefunction
, instance_Fn
* instancefunction
, AggrType aggrType
)
965 mib_tree_entry
*m
, *b
;
971 b
= snmpLookupNodeStr(mib_tree_head
, base_str
);
974 debugs(49, 5, "snmpAddNodeStr: " << base_str
<< ": -> " << b
);
976 /* Create OID string for new entry */
977 snprintf(s
, 1024, "%s.%d", base_str
, o
);
978 if (! snmpCreateOidFromStr(s
, &n
, &nl
))
982 m
= snmpAddNode(n
, nl
, parsefunction
, instancefunction
, aggrType
, 0);
984 /* Link it into the existing tree */
985 snmpAddNodeChild(b
, m
);
987 /* Return the node */
992 * Adds a node to the MIB tree structure and adds the appropriate children
994 static mib_tree_entry
*
995 snmpAddNode(oid
* name
, int len
, oid_ParseFn
* parsefunction
, instance_Fn
* instancefunction
, AggrType aggrType
, int children
,...)
999 mib_tree_entry
*entry
= nullptr;
1000 va_start(args
, children
);
1003 debugs(49, 6, "snmpAddNode: Children : " << children
<< ", Oid : " << snmpDebugOid(name
, len
, tmp
));
1005 va_start(args
, children
);
1006 entry
= (mib_tree_entry
*)xmalloc(sizeof(mib_tree_entry
));
1009 entry
->parsefunction
= parsefunction
;
1010 entry
->instancefunction
= instancefunction
;
1011 entry
->children
= children
;
1012 entry
->leaves
= nullptr;
1013 entry
->aggrType
= aggrType
;
1016 entry
->leaves
= (mib_tree_entry
**)xmalloc(sizeof(mib_tree_entry
*) * children
);
1018 for (loop
= 0; loop
< children
; ++loop
) {
1019 entry
->leaves
[loop
] = va_arg(args
, mib_tree_entry
*);
1020 entry
->leaves
[loop
]->parent
= entry
;
1027 /* End of tree utility functions */
1030 * Returns the list of parameters in an oid
1033 snmpCreateOid(int length
,...)
1038 va_start(args
, length
);
1040 new_oid
= (oid
*)xmalloc(sizeof(oid
) * length
);
1043 for (loop
= 0; loop
< length
; ++loop
) {
1044 new_oid
[loop
] = va_arg(args
, int);
1053 * Debug calls, prints out the OID for debugging purposes.
1056 snmpDebugOid(oid
* Name
, snint Len
, MemBuf
&outbuf
)
1060 if (outbuf
.isNull())
1061 outbuf
.init(16, MAX_IPSTRLEN
);
1063 for (x
= 0; x
< Len
; ++x
) {
1064 size_t bytes
= snprintf(mbuf
, sizeof(mbuf
), ".%u", (unsigned int) Name
[x
]);
1065 outbuf
.append(mbuf
, bytes
);
1067 return outbuf
.content();
1071 snmpSnmplibDebug(int lvl
, char *buf
)
1073 debugs(49, lvl
, buf
);
1077 IPv4 address: 10.10.0.9 ==>
1079 IPv6 address : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01 ==>
1080 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1
1083 addr2oid(Ip::Address
&addr
, oid
* Dest
)
1086 u_char
*cp
= nullptr;
1087 struct in_addr i4addr
;
1088 struct in6_addr i6addr
;
1089 oid code
= addr
.isIPv6()? INETADDRESSTYPE_IPV6
: INETADDRESSTYPE_IPV4
;
1090 u_int size
= (code
== INETADDRESSTYPE_IPV4
) ? sizeof(struct in_addr
):sizeof(struct in6_addr
);
1092 if ( code
== INETADDRESSTYPE_IPV4
) {
1093 addr
.getInAddr(i4addr
);
1094 cp
= (u_char
*) &(i4addr
.s_addr
);
1096 addr
.getInAddr(i6addr
);
1097 cp
= (u_char
*) &i6addr
;
1099 for ( i
=0 ; i
< size
; ++i
) {
1100 // OID's are in network order
1105 debugs(49, 7, "addr2oid: Dest : " << snmpDebugOid(Dest
, size
, tmp
));
1109 oid == 10.10.0.9 ==>
1110 IPv4 address: 10.10.0.9
1111 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1 ==>
1112 IPv6 address : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01
1115 oid2addr(oid
* id
, Ip::Address
&addr
, u_int size
)
1117 struct in_addr i4addr
;
1118 struct in6_addr i6addr
;
1121 if ( size
== sizeof(struct in_addr
) )
1122 cp
= (u_char
*) &(i4addr
.s_addr
);
1124 cp
= (u_char
*) &(i6addr
);
1126 debugs(49, 7, "oid2addr: id : " << snmpDebugOid(id
, size
, tmp
) );
1127 for (i
=0 ; i
<size
; ++i
) {
1130 if ( size
== sizeof(struct in_addr
) )
1137 Acl::SnmpCommunityCheck::match(ACLChecklist
* const ch
)
1139 const auto checklist
= Filled(ch
);
1141 return data
->match (checklist
->snmp_community
);