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