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