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