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