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