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