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