2 * DEBUG: section 49 SNMP support
3 * AUTHOR: Glenn Chisholm
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 #include "acl/FilledChecklist.h"
34 #include "base/CbcPointer.h"
36 #include "comm/Loops.h"
37 #include "ipc/StartListening.h"
38 #include "ip/Address.h"
40 #include "snmp_core.h"
41 #include "snmp/Forwarder.h"
44 /// dials snmpConnectionOpened call
45 class SnmpListeningStartedDialer
: public CallDialer
,
46 public Ipc::StartListeningCb
49 typedef void (*Handler
)(int fd
, int errNo
);
50 SnmpListeningStartedDialer(Handler aHandler
): handler(aHandler
) {}
52 virtual void print(std::ostream
&os
) const { startPrint(os
) << ')'; }
54 virtual bool canDial(AsyncCall
&) const { return true; }
55 virtual void dial(AsyncCall
&) { (handler
)(fd
, errNo
); }
62 Ip::Address theOutSNMPAddr
;
64 mib_tree_entry
*mib_tree_head
;
65 mib_tree_entry
*mib_tree_last
;
67 static void snmpIncomingConnectionOpened(int fd
, int errNo
);
68 static void snmpOutgoingConnectionOpened(int fd
, int errNo
);
70 static mib_tree_entry
* snmpAddNodeStr(const char *base_str
, int o
, oid_ParseFn
* parsefunction
, instance_Fn
* instancefunction
, AggrType aggrType
= atNone
);
71 static mib_tree_entry
*snmpAddNode(oid
* name
, int len
, oid_ParseFn
* parsefunction
, instance_Fn
* instancefunction
, AggrType aggrType
, int children
,...);
72 static oid
*snmpCreateOid(int length
,...);
73 mib_tree_entry
* snmpLookupNodeStr(mib_tree_entry
*entry
, const char *str
);
74 int snmpCreateOidFromStr(const char *str
, oid
**name
, int *nl
);
75 SQUIDCEXTERN
void (*snmplib_debug_hook
) (int, char *);
76 static oid
*static_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
);
77 static oid
*time_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
);
78 static oid
*peer_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
);
79 static oid
*client_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
);
80 static void snmpDecodePacket(snmp_request_t
* rq
);
81 static void snmpConstructReponse(snmp_request_t
* rq
);
83 static oid_ParseFn
*snmpTreeNext(oid
* Current
, snint CurrentLen
, oid
** Next
, snint
* NextLen
);
84 static oid_ParseFn
*snmpTreeGet(oid
* Current
, snint CurrentLen
);
85 static mib_tree_entry
*snmpTreeEntry(oid entry
, snint len
, mib_tree_entry
* current
);
86 static mib_tree_entry
*snmpTreeSiblingEntry(oid entry
, snint len
, mib_tree_entry
* current
);
87 extern "C" void snmpSnmplibDebug(int lvl
, char *buf
);
90 * The functions used during startup:
93 * snmpConnectionShutdown
98 * Turns the MIB into a Tree structure. Called during the startup process.
103 debugs(49, 5, "snmpInit: Building SNMP mib tree structure");
105 snmplib_debug_hook
= snmpSnmplibDebug
;
108 * This following bit of evil is to get the final node in the "squid" mib
109 * without having a "search" function. A search function should be written
110 * to make this and the other code much less evil.
112 mib_tree_head
= snmpAddNode(snmpCreateOid(1, 1), 1, NULL
, NULL
, atNone
, 0);
114 assert(mib_tree_head
);
115 debugs(49, 5, "snmpInit: root is " << mib_tree_head
);
116 snmpAddNodeStr("1", 3, NULL
, NULL
);
118 snmpAddNodeStr("1.3", 6, NULL
, NULL
);
120 snmpAddNodeStr("1.3.6", 1, NULL
, NULL
);
121 snmpAddNodeStr("1.3.6.1", 4, NULL
, NULL
);
122 snmpAddNodeStr("1.3.6.1.4", 1, NULL
, NULL
);
123 snmpAddNodeStr("1.3.6.1.4.1", 3495, NULL
, NULL
);
124 mib_tree_entry
*m2
= snmpAddNodeStr("1.3.6.1.4.1.3495", 1, NULL
, NULL
);
126 mib_tree_entry
*n
= snmpLookupNodeStr(NULL
, "1.3.6.1.4.1.3495.1");
129 /* SQ_SYS - 1.3.6.1.4.1.3495.1.1 */
130 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 1, NULL
, NULL
);
131 snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSVMSIZ
, snmp_sysFn
, static_Inst
, atSum
);
132 snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSSTOR
, snmp_sysFn
, static_Inst
, atSum
);
133 snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYS_UPTIME
, snmp_sysFn
, static_Inst
, atMax
);
135 /* SQ_CONF - 1.3.6.1.4.1.3495.1.2 */
136 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 2, NULL
, NULL
);
137 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_ADMIN
, snmp_confFn
, static_Inst
);
138 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_VERSION
, snmp_confFn
, static_Inst
);
139 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_VERSION_ID
, snmp_confFn
, static_Inst
);
140 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_LOG_FAC
, snmp_confFn
, static_Inst
);
142 /* SQ_CONF + CONF_STORAGE - 1.3.6.1.4.1.3495.1.5 */
143 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_STORAGE
, NULL
, NULL
);
144 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_MMAXSZ
, snmp_confFn
, static_Inst
, atSum
);
145 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWMAXSZ
, snmp_confFn
, static_Inst
, atSum
);
146 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWHIWM
, snmp_confFn
, static_Inst
, atMin
);
147 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWLOWM
, snmp_confFn
, static_Inst
, atMin
);
149 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_UNIQNAME
, snmp_confFn
, static_Inst
);
151 /* SQ_PRF - 1.3.6.1.4.1.3495.1.3 */
152 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 3, NULL
, NULL
); /* SQ_PRF */
154 /* PERF_SYS - 1.3.6.1.4.1.3495.1.3.1 */
155 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3", PERF_SYS
, NULL
, NULL
);
156 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_PF
, snmp_prfSysFn
, static_Inst
, atSum
);
157 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMR
, snmp_prfSysFn
, static_Inst
, atSum
);
158 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MEMUSAGE
, snmp_prfSysFn
, static_Inst
, atSum
);
159 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUTIME
, snmp_prfSysFn
, static_Inst
, atSum
);
160 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUUSAGE
, snmp_prfSysFn
, static_Inst
, atSum
);
161 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MAXRESSZ
, snmp_prfSysFn
, static_Inst
, atSum
);
162 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMOBJCNT
, snmp_prfSysFn
, static_Inst
, atSum
);
165 The meaning of LRU is "oldest timestamped object in cache, if LRU algorithm is
167 What this SMP support needs to do is aggregate via a special filter equivalent to
168 min() to retain the semantic oldest-object meaning. A special one is needed that
169 works as unsigned and ignores '0' values.
171 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURLRUEXP
, snmp_prfSysFn
, static_Inst
);
172 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUNLREQ
, snmp_prfSysFn
, static_Inst
, atSum
);
173 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUNUSED_FD
, snmp_prfSysFn
, static_Inst
, atSum
);
174 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURRESERVED_FD
, snmp_prfSysFn
, static_Inst
, atSum
);
175 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUSED_FD
, snmp_prfSysFn
, static_Inst
, atSum
);
176 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURMAX_FD
, snmp_prfSysFn
, static_Inst
, atMax
);
178 /* PERF_PROTO - 1.3.6.1.4.1.3495.1.3.2 */
179 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3", PERF_PROTO
, NULL
, NULL
);
180 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2", PERF_PROTOSTAT_AGGR
, NULL
, NULL
);
181 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_REQ
, snmp_prfProtoFn
, static_Inst
, atSum
);
182 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_HITS
, snmp_prfProtoFn
, static_Inst
, atSum
);
183 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_ERRORS
, snmp_prfProtoFn
, static_Inst
, atSum
);
184 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_KBYTES_IN
, snmp_prfProtoFn
, static_Inst
, atSum
);
185 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_KBYTES_OUT
, snmp_prfProtoFn
, static_Inst
, atSum
);
186 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_S
, snmp_prfProtoFn
, static_Inst
, atSum
);
187 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_R
, snmp_prfProtoFn
, static_Inst
, atSum
);
188 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_SKB
, snmp_prfProtoFn
, static_Inst
, atSum
);
189 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_RKB
, snmp_prfProtoFn
, static_Inst
, atSum
);
190 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_REQ
, snmp_prfProtoFn
, static_Inst
, atSum
);
191 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ERRORS
, snmp_prfProtoFn
, static_Inst
, atSum
);
192 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_KBYTES_IN
, snmp_prfProtoFn
, static_Inst
, atSum
);
193 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_KBYTES_OUT
, snmp_prfProtoFn
, static_Inst
, atSum
);
194 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_CURSWAP
, snmp_prfProtoFn
, static_Inst
, atSum
);
195 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_CLIENTS
, snmp_prfProtoFn
, static_Inst
, atSum
);
197 /* Note this is time-series rather than 'static' */
198 /* cacheMedianSvcTable */
199 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2", PERF_PROTOSTAT_MEDIAN
, NULL
, NULL
);
201 /* cacheMedianSvcEntry */
202 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2", 1, NULL
, NULL
);
203 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_TIME
, snmp_prfProtoFn
, time_Inst
, atAverage
);
204 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_ALL
, snmp_prfProtoFn
, time_Inst
, atAverage
);
205 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_MISS
, snmp_prfProtoFn
, time_Inst
, atAverage
);
206 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NM
, snmp_prfProtoFn
, time_Inst
, atAverage
);
207 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_HIT
, snmp_prfProtoFn
, time_Inst
, atAverage
);
208 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_QUERY
, snmp_prfProtoFn
, time_Inst
, atAverage
);
209 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_REPLY
, snmp_prfProtoFn
, time_Inst
, atAverage
);
210 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_DNS
, snmp_prfProtoFn
, time_Inst
, atAverage
);
211 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_RHR
, snmp_prfProtoFn
, time_Inst
, atAverage
);
212 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_BHR
, snmp_prfProtoFn
, time_Inst
, atAverage
);
213 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NH
, snmp_prfProtoFn
, time_Inst
, atAverage
);
215 /* SQ_NET - 1.3.6.1.4.1.3495.1.4 */
216 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 4, NULL
, NULL
);
218 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_IP_CACHE
, NULL
, NULL
);
219 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_ENT
, snmp_netIpFn
, static_Inst
, atSum
);
220 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_REQ
, snmp_netIpFn
, static_Inst
, atSum
);
221 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_HITS
, snmp_netIpFn
, static_Inst
, atSum
);
222 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_PENDHIT
, snmp_netIpFn
, static_Inst
, atSum
);
223 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_NEGHIT
, snmp_netIpFn
, static_Inst
, atSum
);
224 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_MISS
, snmp_netIpFn
, static_Inst
, atSum
);
225 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_GHBN
, snmp_netIpFn
, static_Inst
, atSum
);
226 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_LOC
, snmp_netIpFn
, static_Inst
, atSum
);
228 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_FQDN_CACHE
, NULL
, NULL
);
229 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_ENT
, snmp_netFqdnFn
, static_Inst
, atSum
);
230 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_REQ
, snmp_netFqdnFn
, static_Inst
, atSum
);
231 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_HITS
, snmp_netFqdnFn
, static_Inst
, atSum
);
232 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_PENDHIT
, snmp_netFqdnFn
, static_Inst
, atSum
);
233 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_NEGHIT
, snmp_netFqdnFn
, static_Inst
, atSum
);
234 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_MISS
, snmp_netFqdnFn
, static_Inst
, atSum
);
235 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_GHBN
, snmp_netFqdnFn
, static_Inst
, atSum
);
237 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_DNS_CACHE
, NULL
, NULL
);
239 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REQ
, snmp_netDnsFn
, static_Inst
, atSum
);
240 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REP
, snmp_netDnsFn
, static_Inst
, atSum
);
241 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_SERVERS
, snmp_netDnsFn
, static_Inst
, atSum
);
243 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REQ
, snmp_netIdnsFn
, static_Inst
, atSum
);
244 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REP
, snmp_netIdnsFn
, static_Inst
, atSum
);
245 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_SERVERS
, snmp_netIdnsFn
, static_Inst
, atSum
);
248 /* SQ_MESH - 1.3.6.1.4.1.3495.1.5 */
249 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 5, NULL
, NULL
);
251 /* cachePeerTable - 1.3.6.1.4.1.3495.1.5.1 */
252 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5", MESH_PTBL
, NULL
, NULL
);
254 /* CachePeerTableEntry (version 3) - 1.3.6.1.4.1.3495.1.5.1.3 */
255 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1", 3, NULL
, NULL
);
256 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_INDEX
, snmp_meshPtblFn
, peer_Inst
);
257 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_NAME
, snmp_meshPtblFn
, peer_Inst
);
258 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ADDR_TYPE
, snmp_meshPtblFn
, peer_Inst
);
259 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ADDR
, snmp_meshPtblFn
, peer_Inst
);
260 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_HTTP
, snmp_meshPtblFn
, peer_Inst
);
261 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ICP
, snmp_meshPtblFn
, peer_Inst
);
262 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_TYPE
, snmp_meshPtblFn
, peer_Inst
);
263 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_STATE
, snmp_meshPtblFn
, peer_Inst
);
264 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_SENT
, snmp_meshPtblFn
, peer_Inst
);
265 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_PACKED
, snmp_meshPtblFn
, peer_Inst
);
266 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_FETCHES
, snmp_meshPtblFn
, peer_Inst
);
267 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_RTT
, snmp_meshPtblFn
, peer_Inst
);
268 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_IGN
, snmp_meshPtblFn
, peer_Inst
);
269 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_KEEPAL_S
, snmp_meshPtblFn
, peer_Inst
);
270 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_KEEPAL_R
, snmp_meshPtblFn
, peer_Inst
);
272 /* cacheClientTable - 1.3.6.1.4.1.3495.1.5.2 */
273 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5", MESH_CTBL
, NULL
, NULL
);
275 /* BUG 2811: we NEED to create a reliable index for the client DB and make version 3 of the table. */
276 /* for now we have version 2 table with OID capable of mixed IPv4 / IPv6 clients and upgraded address text format. */
278 /* cacheClientEntry - 1.3.6.1.4.1.3495.1.5.2.2 */
279 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2", 2, NULL
, NULL
);
280 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ADDR_TYPE
, snmp_meshCtblFn
, client_Inst
);
281 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ADDR
, snmp_meshCtblFn
, client_Inst
);
282 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTREQ
, snmp_meshCtblFn
, client_Inst
);
283 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTBYTES
, snmp_meshCtblFn
, client_Inst
);
284 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTHITS
, snmp_meshCtblFn
, client_Inst
);
285 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTHITBYTES
, snmp_meshCtblFn
, client_Inst
);
286 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPREQ
, snmp_meshCtblFn
, client_Inst
);
287 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPBYTES
, snmp_meshCtblFn
, client_Inst
);
288 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPHITS
, snmp_meshCtblFn
, client_Inst
);
289 mib_tree_last
= snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPHITBYTES
, snmp_meshCtblFn
, client_Inst
);
291 debugs(49, 9, "snmpInit: Completed SNMP mib tree structure");
295 snmpConnectionOpen(void)
297 debugs(49, 5, "snmpConnectionOpen: Called");
299 if (Config
.Port
.snmp
> 0) {
300 Config
.Addrs
.snmp_incoming
.SetPort(Config
.Port
.snmp
);
302 if (!Ip::EnableIpv6
&& !Config
.Addrs
.snmp_incoming
.SetIPv4()) {
303 debugs(49, DBG_CRITICAL
, "ERROR: IPv6 is disabled. " << Config
.Addrs
.snmp_incoming
<< " is not an IPv4 address.");
304 fatal("SNMP port cannot be opened.");
306 /* split-stack for now requires IPv4-only SNMP */
307 if (Ip::EnableIpv6
&IPV6_SPECIAL_SPLITSTACK
&& Config
.Addrs
.snmp_incoming
.IsAnyAddr()) {
308 Config
.Addrs
.snmp_incoming
.SetIPv4();
311 AsyncCall::Pointer call
= asyncCall(49, 2,
312 "snmpIncomingConnectionOpened",
313 SnmpListeningStartedDialer(&snmpIncomingConnectionOpened
));
315 Ipc::StartListening(SOCK_DGRAM
,
317 Config
.Addrs
.snmp_incoming
,
319 Ipc::fdnInSnmpSocket
, call
);
321 if (!Config
.Addrs
.snmp_outgoing
.IsNoAddr()) {
322 Config
.Addrs
.snmp_outgoing
.SetPort(Config
.Port
.snmp
);
324 if (!Ip::EnableIpv6
&& !Config
.Addrs
.snmp_outgoing
.SetIPv4()) {
325 debugs(49, DBG_CRITICAL
, "ERROR: IPv6 is disabled. " << Config
.Addrs
.snmp_outgoing
<< " is not an IPv4 address.");
326 fatal("SNMP port cannot be opened.");
328 /* split-stack for now requires IPv4-only SNMP */
329 if (Ip::EnableIpv6
&IPV6_SPECIAL_SPLITSTACK
&& Config
.Addrs
.snmp_outgoing
.IsAnyAddr()) {
330 Config
.Addrs
.snmp_outgoing
.SetIPv4();
332 AsyncCall::Pointer call
= asyncCall(49, 2,
333 "snmpOutgoingConnectionOpened",
334 SnmpListeningStartedDialer(&snmpOutgoingConnectionOpened
));
336 Ipc::StartListening(SOCK_DGRAM
,
338 Config
.Addrs
.snmp_outgoing
,
340 Ipc::fdnOutSnmpSocket
, call
);
346 snmpIncomingConnectionOpened(int fd
, int errNo
)
348 theInSnmpConnection
= fd
;
349 if (theInSnmpConnection
< 0)
350 fatal("Cannot open Incoming SNMP Port");
352 Comm::SetSelect(theInSnmpConnection
, COMM_SELECT_READ
, snmpHandleUdp
, NULL
, 0);
354 debugs(1, 1, "Accepting SNMP messages on " << Config
.Addrs
.snmp_incoming
<<
355 ", FD " << theInSnmpConnection
<< ".");
357 if (Config
.Addrs
.snmp_outgoing
.IsNoAddr())
358 theOutSnmpConnection
= theInSnmpConnection
;
362 snmpOutgoingConnectionOpened(int fd
, int errNo
)
364 theOutSnmpConnection
= fd
;
365 if (theOutSnmpConnection
< 0)
366 fatal("Cannot open Outgoing SNMP Port");
368 Comm::SetSelect(theOutSnmpConnection
, COMM_SELECT_READ
, snmpHandleUdp
, NULL
, 0);
370 debugs(1, 1, "Outgoing SNMP messages on " << Config
.Addrs
.snmp_outgoing
<<
371 ", FD " << theOutSnmpConnection
<< ".");
374 struct addrinfo
*xaddr
= NULL
;
378 theOutSNMPAddr
.SetEmpty();
380 theOutSNMPAddr
.InitAddrInfo(xaddr
);
382 x
= getsockname(theOutSnmpConnection
, xaddr
->ai_addr
, &xaddr
->ai_addrlen
);
385 debugs(51, 1, "theOutSnmpConnection FD " << theOutSnmpConnection
<< ": getsockname: " << xstrerror());
387 theOutSNMPAddr
= *xaddr
;
389 theOutSNMPAddr
.FreeAddrInfo(xaddr
);
394 snmpConnectionShutdown(void)
396 if (theInSnmpConnection
< 0)
399 if (theInSnmpConnection
!= theOutSnmpConnection
) {
400 debugs(49, 1, "FD " << theInSnmpConnection
<< " Closing SNMP socket");
401 comm_close(theInSnmpConnection
);
405 * Here we set 'theInSnmpConnection' to -1 even though the SNMP 'in'
406 * and 'out' sockets might be just one FD. This prevents this
407 * function from executing repeatedly. When we are really ready to
408 * exit or restart, main will comm_close the 'out' descriptor.
410 theInSnmpConnection
= -1;
413 * Normally we only write to the outgoing SNMP socket, but we
414 * also have a read handler there to catch messages sent to that
415 * specific interface. During shutdown, we must disable reading
416 * on the outgoing socket.
418 assert(theOutSnmpConnection
> -1);
420 Comm::SetSelect(theOutSnmpConnection
, COMM_SELECT_READ
, NULL
, NULL
, 0);
424 snmpConnectionClose(void)
426 snmpConnectionShutdown();
428 if (theOutSnmpConnection
> -1) {
429 debugs(49, 1, "FD " << theOutSnmpConnection
<< " Closing SNMP socket");
430 comm_close(theOutSnmpConnection
);
431 /* make sure the SNMP out connection is unset */
432 theOutSnmpConnection
= -1;
437 * Functions for handling the requests.
441 * Accept the UDP packet
444 snmpHandleUdp(int sock
, void *not_used
)
446 LOCAL_ARRAY(char, buf
, SNMP_REQUEST_SIZE
);
448 snmp_request_t
*snmp_rq
;
451 debugs(49, 5, "snmpHandleUdp: Called.");
453 Comm::SetSelect(sock
, COMM_SELECT_READ
, snmpHandleUdp
, NULL
, 0);
455 memset(buf
, '\0', SNMP_REQUEST_SIZE
);
457 len
= comm_udp_recvfrom(sock
,
465 debugs(49, 3, "snmpHandleUdp: FD " << sock
<< ": received " << len
<< " bytes from " << from
<< ".");
467 snmp_rq
= (snmp_request_t
*)xcalloc(1, sizeof(snmp_request_t
));
468 snmp_rq
->buf
= (u_char
*) buf
;
470 snmp_rq
->sock
= sock
;
471 snmp_rq
->outbuf
= (unsigned char *)xmalloc(snmp_rq
->outlen
= SNMP_REQUEST_SIZE
);
472 snmp_rq
->from
= from
;
473 snmpDecodePacket(snmp_rq
);
474 xfree(snmp_rq
->outbuf
);
477 debugs(49, 1, "snmpHandleUdp: FD " << sock
<< " recvfrom: " << xstrerror());
482 * Turn SNMP packet into a PDU, check available ACL's
485 snmpDecodePacket(snmp_request_t
* rq
)
487 struct snmp_pdu
*PDU
;
489 u_char
*buf
= rq
->buf
;
493 debugs(49, 5, HERE
<< "Called.");
494 PDU
= snmp_pdu_create(0);
495 /* Allways answer on SNMPv1 */
496 rq
->session
.Version
= SNMP_VERSION_1
;
497 Community
= snmp_parse(&rq
->session
, PDU
, buf
, len
);
499 /* Check if we have explicit permission to access SNMP data.
500 * default (set above) is to deny all */
501 if (Community
&& Config
.accessList
.snmp
) {
502 ACLFilledChecklist
checklist(Config
.accessList
.snmp
, NULL
, NULL
);
503 checklist
.src_addr
= rq
->from
;
504 checklist
.snmp_community
= (char *) Community
;
505 allow
= checklist
.fastCheck();
508 if ((snmp_coexist_V2toV1(PDU
)) && (Community
) && (allow
)) {
509 rq
->community
= Community
;
511 debugs(49, 5, "snmpAgentParse: reqid=[" << PDU
->reqid
<< "]");
512 snmpConstructReponse(rq
);
514 debugs(49, 1, HERE
<< "Failed SNMP agent query from : " << rq
->from
);
523 * Packet OK, ACL Check OK, Create reponse.
526 snmpConstructReponse(snmp_request_t
* rq
)
529 struct snmp_pdu
*RespPDU
;
531 debugs(49, 5, "snmpConstructReponse: Called.");
533 if (UsingSmp() && IamWorkerProcess()) {
534 AsyncJob::Start(new Snmp::Forwarder(static_cast<Snmp::Pdu
&>(*rq
->PDU
),
535 static_cast<Snmp::Session
&>(rq
->session
), rq
->sock
, rq
->from
));
536 snmp_free_pdu(rq
->PDU
);
540 RespPDU
= snmpAgentResponse(rq
->PDU
);
541 snmp_free_pdu(rq
->PDU
);
543 if (RespPDU
!= NULL
) {
544 snmp_build(&rq
->session
, RespPDU
, rq
->outbuf
, &rq
->outlen
);
545 comm_udp_sendto(rq
->sock
, rq
->from
, rq
->outbuf
, rq
->outlen
);
546 snmp_free_pdu(RespPDU
);
551 * Decide how to respond to the request, construct a response and
552 * return the response to the requester.
556 snmpAgentResponse(struct snmp_pdu
*PDU
) {
558 struct snmp_pdu
*Answer
= NULL
;
560 debugs(49, 5, "snmpAgentResponse: Called.");
562 if ((Answer
= snmp_pdu_create(SNMP_PDU_RESPONSE
))) {
563 Answer
->reqid
= PDU
->reqid
;
564 Answer
->errindex
= 0;
566 if (PDU
->command
== SNMP_PDU_GET
|| PDU
->command
== SNMP_PDU_GETNEXT
) {
568 int get_next
= (PDU
->command
== SNMP_PDU_GETNEXT
);
569 variable_list
*VarPtr_
;
570 variable_list
**RespVars
= &(Answer
->variables
);
571 oid_ParseFn
*ParseFn
;
573 /* Loop through all variables */
575 for (VarPtr_
= PDU
->variables
; VarPtr_
; VarPtr_
= VarPtr_
->next_variable
) {
576 variable_list
*VarPtr
= VarPtr_
;
577 variable_list
*VarNew
= NULL
;
578 oid
*NextOidName
= NULL
;
579 snint NextOidNameLen
= 0;
584 ParseFn
= snmpTreeNext(VarPtr
->name
, VarPtr
->name_length
, &NextOidName
, &NextOidNameLen
);
586 ParseFn
= snmpTreeGet(VarPtr
->name
, VarPtr
->name_length
);
588 if (ParseFn
== NULL
) {
589 Answer
->errstat
= SNMP_ERR_NOSUCHNAME
;
590 debugs(49, 5, "snmpAgentResponse: No such oid. ");
593 VarPtr
= snmp_var_new(NextOidName
, NextOidNameLen
);
597 int * errstatTmp
= &(Answer
->errstat
);
599 VarNew
= (*ParseFn
) (VarPtr
, (snint
*) errstatTmp
);
602 snmp_var_free(VarPtr
);
605 if ((Answer
->errstat
!= SNMP_ERR_NOERROR
) || (VarNew
== NULL
)) {
606 Answer
->errindex
= index
;
607 debugs(49, 5, "snmpAgentResponse: error.");
610 snmp_var_free(VarNew
);
612 while ((VarPtr
= Answer
->variables
) != NULL
) {
613 Answer
->variables
= VarPtr
->next_variable
;
614 snmp_var_free(VarPtr
);
617 /* Steal the original PDU list of variables for the error response */
618 Answer
->variables
= PDU
->variables
;
620 PDU
->variables
= NULL
;
625 /* No error. Insert this var at the end, and move on to the next.
629 RespVars
= &(VarNew
->next_variable
);
638 snmpTreeGet(oid
* Current
, snint CurrentLen
)
640 oid_ParseFn
*Fn
= NULL
;
641 mib_tree_entry
*mibTreeEntry
= NULL
;
644 debugs(49, 5, "snmpTreeGet: Called");
647 debugs(49, 6, "snmpTreeGet: Current : " << snmpDebugOid(Current
, CurrentLen
, tmp
) );
649 mibTreeEntry
= mib_tree_head
;
651 if (Current
[count
] == mibTreeEntry
->name
[count
]) {
654 while ((mibTreeEntry
) && (count
< CurrentLen
) && (!mibTreeEntry
->parsefunction
)) {
655 mibTreeEntry
= snmpTreeEntry(Current
[count
], count
, mibTreeEntry
);
660 if (mibTreeEntry
&& mibTreeEntry
->parsefunction
)
661 Fn
= mibTreeEntry
->parsefunction
;
663 debugs(49, 5, "snmpTreeGet: return");
669 snmpAggrType(oid
* Current
, snint CurrentLen
)
673 mib_tree_entry
* mibTreeEntry
= mib_tree_head
;
674 AggrType type
= atNone
;
677 if (Current
[count
] == mibTreeEntry
->name
[count
]) {
680 while (mibTreeEntry
!= NULL
&& count
< CurrentLen
) {
681 mibTreeEntry
= snmpTreeEntry(Current
[count
], count
, mibTreeEntry
);
682 if (mibTreeEntry
!= NULL
)
683 type
= mibTreeEntry
->aggrType
;
692 snmpTreeNext(oid
* Current
, snint CurrentLen
, oid
** Next
, snint
* NextLen
)
694 oid_ParseFn
*Fn
= NULL
;
695 mib_tree_entry
*mibTreeEntry
= NULL
, *nextoid
= NULL
;
698 debugs(49, 5, "snmpTreeNext: Called");
701 debugs(49, 6, "snmpTreeNext: Current : " << snmpDebugOid(Current
, CurrentLen
, tmp
));
703 mibTreeEntry
= mib_tree_head
;
705 if (Current
[count
] == mibTreeEntry
->name
[count
]) {
708 while ((mibTreeEntry
) && (count
< CurrentLen
) && (!mibTreeEntry
->parsefunction
)) {
709 mib_tree_entry
*nextmibTreeEntry
= snmpTreeEntry(Current
[count
], count
, mibTreeEntry
);
711 if (!nextmibTreeEntry
)
714 mibTreeEntry
= nextmibTreeEntry
;
718 debugs(49, 5, "snmpTreeNext: Recursed down to requested object");
723 if (mibTreeEntry
== mib_tree_last
)
727 if ((mibTreeEntry
) && (mibTreeEntry
->parsefunction
)) {
728 *NextLen
= CurrentLen
;
729 *Next
= (*mibTreeEntry
->instancefunction
) (Current
, NextLen
, mibTreeEntry
, &Fn
);
732 debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next
, *NextLen
, tmp
));
737 if ((mibTreeEntry
) && (mibTreeEntry
->parsefunction
)) {
739 nextoid
= snmpTreeSiblingEntry(Current
[count
], count
, mibTreeEntry
->parent
);
741 debugs(49, 5, "snmpTreeNext: Next OID found for sibling" << nextoid
);
742 mibTreeEntry
= nextoid
;
745 debugs(49, 5, "snmpTreeNext: Attempting to recurse up for next object");
750 if (mibTreeEntry
->parent
->parent
) {
751 nextoid
= mibTreeEntry
->parent
;
752 mibTreeEntry
= snmpTreeEntry(Current
[count
] + 1, count
, nextoid
->parent
);
755 mibTreeEntry
= nextoid
;
759 nextoid
= mibTreeEntry
;
765 while ((mibTreeEntry
) && (!mibTreeEntry
->parsefunction
)) {
766 mibTreeEntry
= mibTreeEntry
->leaves
[0];
770 *NextLen
= mibTreeEntry
->len
;
771 *Next
= (*mibTreeEntry
->instancefunction
) (mibTreeEntry
->name
, NextLen
, mibTreeEntry
, &Fn
);
776 debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next
, *NextLen
, tmp
));
783 static_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
)
785 oid
*instance
= NULL
;
786 if (*len
<= current
->len
) {
787 instance
= (oid
*)xmalloc(sizeof(name
) * (*len
+ 1));
788 memcpy(instance
, name
, (sizeof(name
) * *len
));
792 *Fn
= current
->parsefunction
;
797 time_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
)
799 oid
*instance
= NULL
;
800 int identifier
= 0, loop
= 0;
801 int index
[TIME_INDEX_LEN
] = {TIME_INDEX
};
803 if (*len
<= current
->len
) {
804 instance
= (oid
*)xmalloc(sizeof(name
) * (*len
+ 1));
805 memcpy(instance
, name
, (sizeof(name
) * *len
));
806 instance
[*len
] = *index
;
809 identifier
= name
[*len
- 1];
811 while ((loop
< TIME_INDEX_LEN
) && (identifier
!= index
[loop
]))
814 if (loop
< (TIME_INDEX_LEN
- 1)) {
815 instance
= (oid
*)xmalloc(sizeof(name
) * (*len
));
816 memcpy(instance
, name
, (sizeof(name
) * *len
));
817 instance
[*len
- 1] = index
[++loop
];
821 *Fn
= current
->parsefunction
;
827 peer_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
)
829 oid
*instance
= NULL
;
830 peer
*peers
= Config
.peers
;
833 debugs(49, 6, "snmp peer_Inst: No Peers.");
834 current
= current
->parent
->parent
->parent
->leaves
[1];
835 while ((current
) && (!current
->parsefunction
))
836 current
= current
->leaves
[0];
838 instance
= client_Inst(current
->name
, len
, current
, Fn
);
839 } else if (*len
<= current
->len
) {
840 debugs(49, 6, "snmp peer_Inst: *len <= current->len ???");
841 instance
= (oid
*)xmalloc(sizeof(name
) * ( *len
+ 1));
842 memcpy(instance
, name
, (sizeof(name
) * *len
));
846 int no
= name
[current
->len
] ;
848 // Note: This works because the Config.peers keeps its index according to its position.
849 for ( i
=0 ; peers
&& (i
< no
) ; peers
= peers
->next
, i
++ ) ;
852 debugs(49, 6, "snmp peer_Inst: Encode peer #" << i
);
853 instance
= (oid
*)xmalloc(sizeof(name
) * (current
->len
+ 1 ));
854 memcpy(instance
, name
, (sizeof(name
) * current
->len
));
855 instance
[current
->len
] = no
+ 1 ; // i.e. the next index on cache_peeer table.
857 debugs(49, 6, "snmp peer_Inst: We have " << i
<< " peers. Can't find #" << no
);
861 *Fn
= current
->parsefunction
;
866 client_Inst(oid
* name
, snint
* len
, mib_tree_entry
* current
, oid_ParseFn
** Fn
)
868 oid
*instance
= NULL
;
874 if (*len
<= current
->len
) {
875 aux
= client_entry(NULL
);
882 size
= sizeof(in_addr
);
884 size
= sizeof(in6_addr
);
886 debugs(49, 6, HERE
<< "len" << *len
<< ", current-len" << current
->len
<< ", addr=" << laddr
<< ", size=" << size
);
888 instance
= (oid
*)xmalloc(sizeof(name
) * (*len
+ size
));
889 memcpy(instance
, name
, (sizeof(name
) * (*len
)));
891 if ( !laddr
.IsAnyAddr() ) {
892 addr2oid(laddr
, &instance
[ *len
]); // the addr
896 int shift
= *len
- current
->len
; // i.e 4 or 16
897 oid2addr(&name
[*len
- shift
], laddr
,shift
);
898 aux
= client_entry(&laddr
);
904 if (!laddr
.IsAnyAddr()) {
906 newshift
= sizeof(in_addr
);
908 newshift
= sizeof(in6_addr
);
910 debugs(49, 6, HERE
<< "len" << *len
<< ", current-len" << current
->len
<< ", addr=" << laddr
<< ", newshift=" << newshift
);
912 instance
= (oid
*)xmalloc(sizeof(name
) * (current
->len
+ newshift
));
913 memcpy(instance
, name
, (sizeof(name
) * (current
->len
)));
914 addr2oid(laddr
, &instance
[current
->len
]); // the addr.
915 *len
= current
->len
+ newshift
;
919 *Fn
= current
->parsefunction
;
928 * Tree utility functions.
932 * Returns a sibling object for the requested child object or NULL
933 * if it does not exit
935 static mib_tree_entry
*
936 snmpTreeSiblingEntry(oid entry
, snint len
, mib_tree_entry
* current
)
938 mib_tree_entry
*next
= NULL
;
941 while ((!next
) && (count
< current
->children
)) {
942 if (current
->leaves
[count
]->name
[len
] == entry
) {
943 next
= current
->leaves
[count
];
949 /* Exactly the sibling on right */
950 if (count
< current
->children
) {
951 next
= current
->leaves
[count
];
960 * Returns the requested child object or NULL if it does not exist
962 static mib_tree_entry
*
963 snmpTreeEntry(oid entry
, snint len
, mib_tree_entry
* current
)
965 mib_tree_entry
*next
= NULL
;
968 while ((!next
) && current
&& (count
< current
->children
)) {
969 if (current
->leaves
[count
]->name
[len
] == entry
) {
970 next
= current
->leaves
[count
];
980 snmpAddNodeChild(mib_tree_entry
*entry
, mib_tree_entry
*child
)
982 debugs(49, 5, "snmpAddNodeChild: assigning " << child
<< " to parent " << entry
);
983 entry
->leaves
= (mib_tree_entry
**)xrealloc(entry
->leaves
, sizeof(mib_tree_entry
*) * (entry
->children
+ 1));
984 entry
->leaves
[entry
->children
] = child
;
985 entry
->leaves
[entry
->children
]->parent
= entry
;
990 snmpLookupNodeStr(mib_tree_entry
*root
, const char *str
)
1001 if (! snmpCreateOidFromStr(str
, &name
, &namelen
))
1004 /* I wish there were some kind of sensible existing tree traversal
1005 * routine to use. I'll worry about that later */
1008 return e
; /* XXX it should only be this? */
1012 while (r
< namelen
) {
1014 /* Find the child node which matches this */
1015 for (i
= 0; i
< e
->children
&& e
->leaves
[i
]->name
[r
] != name
[r
]; i
++) ; // seek-loop
1017 /* Are we pointing to that node? */
1018 if (i
>= e
->children
)
1020 assert(e
->leaves
[i
]->name
[r
] == name
[r
]);
1022 /* Skip to that node! */
1032 snmpCreateOidFromStr(const char *str
, oid
**name
, int *nl
)
1034 char const *delim
= ".";
1039 char *s
= xstrdup(str
);
1042 /* Parse the OID string into oid bits */
1043 while ( (p
= strsep(&s_
, delim
)) != NULL
) {
1044 *name
= (oid
*)xrealloc(*name
, sizeof(oid
) * ((*nl
) + 1));
1045 (*name
)[*nl
] = atoi(p
);
1054 * Create an entry. Return a pointer to the newly created node, or NULL
1057 static mib_tree_entry
*
1058 snmpAddNodeStr(const char *base_str
, int o
, oid_ParseFn
* parsefunction
, instance_Fn
* instancefunction
, AggrType aggrType
)
1060 mib_tree_entry
*m
, *b
;
1065 /* Find base node */
1066 b
= snmpLookupNodeStr(mib_tree_head
, base_str
);
1069 debugs(49, 5, "snmpAddNodeStr: " << base_str
<< ": -> " << b
);
1071 /* Create OID string for new entry */
1072 snprintf(s
, 1024, "%s.%d", base_str
, o
);
1073 if (! snmpCreateOidFromStr(s
, &n
, &nl
))
1077 m
= snmpAddNode(n
, nl
, parsefunction
, instancefunction
, aggrType
, 0);
1079 /* Link it into the existing tree */
1080 snmpAddNodeChild(b
, m
);
1082 /* Return the node */
1088 * Adds a node to the MIB tree structure and adds the appropriate children
1090 static mib_tree_entry
*
1091 snmpAddNode(oid
* name
, int len
, oid_ParseFn
* parsefunction
, instance_Fn
* instancefunction
, AggrType aggrType
, int children
,...)
1095 mib_tree_entry
*entry
= NULL
;
1096 va_start(args
, children
);
1099 debugs(49, 6, "snmpAddNode: Children : " << children
<< ", Oid : " << snmpDebugOid(name
, len
, tmp
));
1101 va_start(args
, children
);
1102 entry
= (mib_tree_entry
*)xmalloc(sizeof(mib_tree_entry
));
1105 entry
->parsefunction
= parsefunction
;
1106 entry
->instancefunction
= instancefunction
;
1107 entry
->children
= children
;
1108 entry
->leaves
= NULL
;
1109 entry
->aggrType
= aggrType
;
1112 entry
->leaves
= (mib_tree_entry
**)xmalloc(sizeof(mib_tree_entry
*) * children
);
1114 for (loop
= 0; loop
< children
; loop
++) {
1115 entry
->leaves
[loop
] = va_arg(args
, mib_tree_entry
*);
1116 entry
->leaves
[loop
]->parent
= entry
;
1122 /* End of tree utility functions */
1125 * Returns the list of parameters in an oid
1128 snmpCreateOid(int length
,...)
1133 va_start(args
, length
);
1135 new_oid
= (oid
*)xmalloc(sizeof(oid
) * length
);
1138 for (loop
= 0; loop
< length
; loop
++) {
1139 new_oid
[loop
] = va_arg(args
, int);
1147 * Debug calls, prints out the OID for debugging purposes.
1150 snmpDebugOid(oid
* Name
, snint Len
, MemBuf
&outbuf
)
1154 if (outbuf
.isNull())
1155 outbuf
.init(16, MAX_IPSTRLEN
);
1157 for (x
= 0; x
< Len
; x
++) {
1158 size_t bytes
= snprintf(mbuf
, sizeof(mbuf
), ".%u", (unsigned int) Name
[x
]);
1159 outbuf
.append(mbuf
, bytes
);
1161 return outbuf
.content();
1165 snmpSnmplibDebug(int lvl
, char *buf
)
1167 debugs(49, lvl
, buf
);
1173 IPv4 address: 10.10.0.9 ==>
1175 IPv6 adress : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01 ==>
1176 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1
1179 addr2oid(Ip::Address
&addr
, oid
* Dest
)
1183 struct in_addr i4addr
;
1184 struct in6_addr i6addr
;
1185 oid code
= addr
.IsIPv6()? INETADDRESSTYPE_IPV6
: INETADDRESSTYPE_IPV4
;
1186 u_int size
= (code
== INETADDRESSTYPE_IPV4
) ? sizeof(struct in_addr
):sizeof(struct in6_addr
);
1188 if ( code
== INETADDRESSTYPE_IPV4
) {
1189 addr
.GetInAddr(i4addr
);
1190 cp
= (u_char
*) &(i4addr
.s_addr
);
1192 addr
.GetInAddr(i6addr
);
1193 cp
= (u_char
*) &i6addr
;
1195 for ( i
=0 ; i
< size
; i
++) {
1196 // OID's are in network order
1200 debugs(49, 7, "addr2oid: Dest : " << snmpDebugOid(Dest
, size
, tmp
));
1204 oid == 10.10.0.9 ==>
1205 IPv4 address: 10.10.0.9
1206 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1 ==>
1207 IPv6 adress : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01
1210 oid2addr(oid
* id
, Ip::Address
&addr
, u_int size
)
1212 struct in_addr i4addr
;
1213 struct in6_addr i6addr
;
1216 if ( size
== sizeof(struct in_addr
) )
1217 cp
= (u_char
*) &(i4addr
.s_addr
);
1219 cp
= (u_char
*) &(i6addr
);
1221 debugs(49, 7, "oid2addr: id : " << snmpDebugOid(id
, size
, tmp
) );
1222 for (i
=0 ; i
<size
; i
++) {
1225 if ( size
== sizeof(struct in_addr
) )
1231 /* SNMP checklists */
1232 #include "acl/Strategy.h"
1233 #include "acl/Strategised.h"
1234 #include "acl/StringData.h"
1236 class ACLSNMPCommunityStrategy
: public ACLStrategy
<char const *>
1240 virtual int match (ACLData
<MatchType
> * &, ACLFilledChecklist
*);
1241 static ACLSNMPCommunityStrategy
*Instance();
1242 /* Not implemented to prevent copies of the instance. */
1243 /* Not private to prevent brain dead g+++ warnings about
1244 * private constructors with no friends */
1245 ACLSNMPCommunityStrategy(ACLSNMPCommunityStrategy
const &);
1248 static ACLSNMPCommunityStrategy Instance_
;
1249 ACLSNMPCommunityStrategy() {}
1251 ACLSNMPCommunityStrategy
&operator=(ACLSNMPCommunityStrategy
const &);
1254 class ACLSNMPCommunity
1258 static ACL::Prototype RegistryProtoype
;
1259 static ACLStrategised
<char const *> RegistryEntry_
;
1262 ACL::Prototype
ACLSNMPCommunity::RegistryProtoype(&ACLSNMPCommunity::RegistryEntry_
, "snmp_community");
1263 ACLStrategised
<char const *> ACLSNMPCommunity::RegistryEntry_(new ACLStringData
, ACLSNMPCommunityStrategy::Instance(), "snmp_community");
1266 ACLSNMPCommunityStrategy::match (ACLData
<MatchType
> * &data
, ACLFilledChecklist
*checklist
)
1268 return data
->match (checklist
->snmp_community
);
1271 ACLSNMPCommunityStrategy
*
1272 ACLSNMPCommunityStrategy::Instance()
1277 ACLSNMPCommunityStrategy
ACLSNMPCommunityStrategy::Instance_
;