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