]> git.ipfire.org Git - thirdparty/squid.git/blob - src/snmp_core.cc
2.1 branch merge
[thirdparty/squid.git] / src / snmp_core.cc
1 /*
2 * $Id: snmp_core.cc,v 1.14 1998/11/12 06:28:23 wessels Exp $
3 *
4 * DEBUG: section 49 SNMP support
5 * AUTHOR: Glenn Chisholm
6 *
7 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from the
11 * Internet community. Development is led by Duane Wessels of the
12 * National Laboratory for Applied Network Research and funded by the
13 * National Science Foundation. Squid is Copyrighted (C) 1998 by
14 * Duane Wessels and the University of California San Diego. Please
15 * see the COPYRIGHT file for full details. Squid incorporates
16 * software developed and/or copyrighted by other sources. Please see
17 * the CREDITS file for full details.
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 */
34 #include "squid.h"
35 #include "cache_snmp.h"
36
37 #define SNMP_REQUEST_SIZE 4096
38 #define MAX_PROTOSTAT 5
39
40 struct _mib_tree_entry {
41 oid *name;
42 int len;
43 oid_ParseFn *parsefunction;
44 int children;
45 struct _mib_tree_entry **leaves;
46 struct _mib_tree_entry *parent;
47 };
48
49 struct _snmpUdpData {
50 struct sockaddr_in address;
51 void *msg;
52 int len;
53 struct _snmpUdpData *next;
54 };
55
56 typedef struct _snmpUdpData snmpUdpData;
57 typedef struct _mib_tree_entry mib_tree_entry;
58
59 mib_tree_entry *mib_tree_head;
60 snmpUdpData *snmpUdpHead = NULL;
61 snmpUdpData *snmpUdpTail = NULL;
62
63 extern void (*snmplib_debug_hook) (int, char *);
64
65 static void snmpDecodePacket(snmp_request_t * rq);
66 static void snmpConstructReponse(snmp_request_t * rq, struct snmp_session *Session);
67 static struct snmp_pdu *snmpAgentResponse(struct snmp_pdu *PDU);
68
69 static void snmpUdpSend(int, const struct sockaddr_in *, void *, int);
70 static void snmpUdpReply(int, void *);
71 static void snmpAppendUdp(snmpUdpData *);
72
73
74 static mib_tree_entry *snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, int children,...);
75 static oid_ParseFn *snmpTreeNext(oid * Current, snint CurrentLen, oid ** Next, snint * NextLen);
76 static mib_tree_entry *snmpTreeEntry(oid entry, snint len, mib_tree_entry * current);
77
78 static oid *snmpCreateOid(int length,...);
79 static oid *snmpOidDup(oid * A, snint ALen);
80 static void snmpSnmplibDebug(int lvl, char *buf);
81
82
83 /*
84 * The functions used during startup:
85 * snmpInit
86 * snmpConnectionOpen
87 * snmpConnectionShutdown
88 * snmpConnectionClose
89 */
90
91 /*
92 * Turns the MIB into a Tree structure. Called during the startup process.
93 */
94 void
95 snmpInit(void)
96 {
97 debug(49, 5) ("snmpInit: Called.\n");
98
99 debug(49, 5) ("snmpInit: Building SNMP mib tree structure\n");
100
101 snmplib_debug_hook = snmpSnmplibDebug;
102
103 mib_tree_head = snmpAddNode(snmpCreateOid(1, 1),
104 1, NULL, 1,
105 snmpAddNode(snmpCreateOid(2, 1, 3),
106 2, NULL, 1,
107 snmpAddNode(snmpCreateOid(3, 1, 3, 6),
108 3, NULL, 1,
109 snmpAddNode(snmpCreateOid(4, 1, 3, 6, 1),
110 4, NULL, 1,
111 snmpAddNode(snmpCreateOid(5, 1, 3, 6, 1, 4),
112 5, NULL, 1,
113 snmpAddNode(snmpCreateOid(6, 1, 3, 6, 1, 4, 1),
114 6, NULL, 1,
115 snmpAddNode(snmpCreateOid(7, 1, 3, 6, 1, 4, 1, 3495),
116 7, NULL, 1,
117 snmpAddNode(snmpCreateOid(LEN_SQUIDMIB, SQUIDMIB),
118 8, NULL, 5,
119 snmpAddNode(snmpCreateOid(LEN_SQ_SYS, SQ_SYS),
120 LEN_SQ_SYS, NULL, 3,
121 snmpAddNode(snmpCreateOid(LEN_SQ_SYS + 1, SQ_SYS, 1),
122 LEN_SQ_SYS + 1, snmp_sysFn, 0),
123 snmpAddNode(snmpCreateOid(LEN_SQ_SYS + 1, SQ_SYS, 2),
124 LEN_SQ_SYS + 1, snmp_sysFn, 0),
125 snmpAddNode(snmpCreateOid(LEN_SQ_SYS + 1, SQ_SYS, 3),
126 LEN_SQ_SYS + 1, snmp_sysFn, 0)),
127 snmpAddNode(snmpCreateOid(LEN_SQ_CONF, SQ_CONF),
128 LEN_SQ_CONF, NULL, 5,
129 snmpAddNode(snmpCreateOid(LEN_SQ_CONF + 1, SQ_CONF, 1),
130 LEN_SQ_CONF + 1, snmp_confFn, 0),
131 snmpAddNode(snmpCreateOid(LEN_SQ_CONF + 1, SQ_CONF, 2),
132 LEN_SQ_CONF + 1, snmp_confFn, 0),
133 snmpAddNode(snmpCreateOid(LEN_SQ_CONF + 1, SQ_CONF, 3),
134 LEN_SQ_CONF + 1, snmp_confFn, 0),
135 snmpAddNode(snmpCreateOid(LEN_SQ_CONF + 1, SQ_CONF, 4),
136 LEN_SQ_CONF + 1, snmp_confFn, 0),
137 snmpAddNode(snmpCreateOid(LEN_SQ_CONF + 1, SQ_CONF, 5),
138 LEN_SQ_CONF + 1, NULL, 6,
139 snmpAddNode(snmpCreateOid(LEN_SQ_CONF + 2, SQ_CONF, 5, 1),
140 LEN_SQ_CONF + 2, snmp_confFn, 0),
141 snmpAddNode(snmpCreateOid(LEN_SQ_CONF + 2, SQ_CONF, 5, 2),
142 LEN_SQ_CONF + 2, snmp_confFn, 0),
143 snmpAddNode(snmpCreateOid(LEN_SQ_CONF + 2, SQ_CONF, 5, 3),
144 LEN_SQ_CONF + 2, snmp_confFn, 0),
145 snmpAddNode(snmpCreateOid(LEN_SQ_CONF + 2, SQ_CONF, 5, 4),
146 LEN_SQ_CONF + 2, snmp_confFn, 0),
147 snmpAddNode(snmpCreateOid(LEN_SQ_CONF + 2, SQ_CONF, 5, 5),
148 LEN_SQ_CONF + 2, snmp_confFn, 0),
149 snmpAddNode(snmpCreateOid(LEN_SQ_CONF + 2, SQ_CONF, 5, 6),
150 LEN_SQ_CONF + 2, snmp_confFn, 0))),
151 snmpAddNode(snmpCreateOid(LEN_SQ_PRF, SQ_PRF),
152 LEN_SQ_PRF, snmp_confFn, 2,
153 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 1, SQ_PRF, 1),
154 LEN_SQ_PRF + 1, snmp_sysFn, 11,
155 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 2, SQ_PRF, 1, 1),
156 LEN_SQ_PRF + 2, snmp_sysFn, 0),
157 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 2, SQ_PRF, 1, 2),
158 LEN_SQ_PRF + 2, snmp_sysFn, 0),
159 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 2, SQ_PRF, 1, 3),
160 LEN_SQ_PRF + 2, snmp_sysFn, 0),
161 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 2, SQ_PRF, 1, 4),
162 LEN_SQ_PRF + 2, snmp_sysFn, 0),
163 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 2, SQ_PRF, 1, 5),
164 LEN_SQ_PRF + 2, snmp_sysFn, 0),
165 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 2, SQ_PRF, 1, 6),
166 LEN_SQ_PRF + 2, snmp_sysFn, 0),
167 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 2, SQ_PRF, 1, 7),
168 LEN_SQ_PRF + 2, snmp_sysFn, 0),
169 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 2, SQ_PRF, 1, 8),
170 LEN_SQ_PRF + 2, snmp_sysFn, 0),
171 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 2, SQ_PRF, 1, 9),
172 LEN_SQ_PRF + 2, snmp_sysFn, 0),
173 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 2, SQ_PRF, 1, 10),
174 LEN_SQ_PRF + 2, snmp_sysFn, 0),
175 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 2, SQ_PRF, 1, 11),
176 LEN_SQ_PRF + 2, snmp_sysFn, 0)),
177 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 1, SQ_PRF, 2),
178 LEN_SQ_PRF + 1, snmp_sysFn, 2,
179 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 2, SQ_PRF, 2, 1),
180 LEN_SQ_PRF + 2, snmp_sysFn, 14,
181 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 1),
182 LEN_SQ_PRF + 3, snmp_sysFn, 0),
183 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 2),
184 LEN_SQ_PRF + 3, snmp_sysFn, 0),
185 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 3),
186 LEN_SQ_PRF + 3, snmp_sysFn, 0),
187 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 4),
188 LEN_SQ_PRF + 3, snmp_sysFn, 0),
189 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 5),
190 LEN_SQ_PRF + 3, snmp_sysFn, 0),
191 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 6),
192 LEN_SQ_PRF + 3, snmp_sysFn, 0),
193 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 7),
194 LEN_SQ_PRF + 3, snmp_sysFn, 0),
195 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 8),
196 LEN_SQ_PRF + 3, snmp_sysFn, 0),
197 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 9),
198 LEN_SQ_PRF + 3, snmp_sysFn, 0),
199 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 10),
200 LEN_SQ_PRF + 3, snmp_sysFn, 0),
201 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 11),
202 LEN_SQ_PRF + 3, snmp_sysFn, 0),
203 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 12),
204 LEN_SQ_PRF + 3, snmp_sysFn, 0),
205 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 13),
206 LEN_SQ_PRF + 3, snmp_sysFn, 0),
207 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 1, 14),
208 LEN_SQ_PRF + 3, snmp_sysFn, 0)),
209 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 2, SQ_PRF, 2, 2),
210 LEN_SQ_PRF + 2, snmp_sysFn, 1,
211 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 3, SQ_PRF, 2, 2, 1),
212 LEN_SQ_PRF + 3, snmp_sysFn, 8,
213 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 4, SQ_PRF, 2, 2, 1, 1),
214 LEN_SQ_PRF + 4, snmp_sysFn, 0),
215 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 4, SQ_PRF, 2, 2, 1, 2),
216 LEN_SQ_PRF + 4, snmp_sysFn, 0),
217 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 4, SQ_PRF, 2, 2, 1, 3),
218 LEN_SQ_PRF + 4, snmp_sysFn, 0),
219 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 4, SQ_PRF, 2, 2, 1, 4),
220 LEN_SQ_PRF + 4, snmp_sysFn, 0),
221 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 4, SQ_PRF, 2, 2, 1, 5),
222 LEN_SQ_PRF + 4, snmp_sysFn, 0),
223 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 4, SQ_PRF, 2, 2, 1, 6),
224 LEN_SQ_PRF + 4, snmp_sysFn, 0),
225 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 4, SQ_PRF, 2, 2, 1, 7),
226 LEN_SQ_PRF + 4, snmp_sysFn, 0),
227 snmpAddNode(snmpCreateOid(LEN_SQ_PRF + 4, SQ_PRF, 2, 2, 1, 8),
228 LEN_SQ_PRF + 4, snmp_sysFn, 0))))),
229 snmpAddNode(snmpCreateOid(LEN_SQ_NET, SQ_NET),
230 LEN_SQ_NET, snmp_confFn, 3,
231 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 1, SQ_NET, 1),
232 LEN_SQ_NET + 1, snmp_sysFn, 9,
233 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 1, 1),
234 LEN_SQ_NET + 2, snmp_sysFn, 0),
235 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 1, 2),
236 LEN_SQ_NET + 2, snmp_sysFn, 0),
237 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 1, 3),
238 LEN_SQ_NET + 2, snmp_sysFn, 0),
239 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 1, 4),
240 LEN_SQ_NET + 2, snmp_sysFn, 0),
241 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 1, 5),
242 LEN_SQ_NET + 2, snmp_sysFn, 0),
243 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 1, 6),
244 LEN_SQ_NET + 2, snmp_sysFn, 0),
245 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 1, 7),
246 LEN_SQ_NET + 2, snmp_sysFn, 0),
247 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 1, 8),
248 LEN_SQ_NET + 2, snmp_sysFn, 0),
249 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 1, 9),
250 LEN_SQ_NET + 2, snmp_sysFn, 0)),
251 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 1, SQ_NET, 2),
252 LEN_SQ_NET + 1, snmp_sysFn, 8,
253 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 2, 1),
254 LEN_SQ_NET + 2, snmp_sysFn, 0),
255 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 2, 2),
256 LEN_SQ_NET + 2, snmp_sysFn, 0),
257 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 2, 3),
258 LEN_SQ_NET + 2, snmp_sysFn, 0),
259 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 2, 4),
260 LEN_SQ_NET + 2, snmp_sysFn, 0),
261 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 2, 5),
262 LEN_SQ_NET + 2, snmp_sysFn, 0),
263 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 2, 6),
264 LEN_SQ_NET + 2, snmp_sysFn, 0),
265 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 2, 7),
266 LEN_SQ_NET + 2, snmp_sysFn, 0),
267 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 2, 8),
268 LEN_SQ_NET + 2, snmp_sysFn, 0)),
269 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 1, SQ_NET, 3),
270 LEN_SQ_NET + 1, snmp_sysFn, 3,
271 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 3, 1),
272 LEN_SQ_NET + 2, snmp_sysFn, 0),
273 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 3, 2),
274 LEN_SQ_NET + 2, snmp_sysFn, 0),
275 snmpAddNode(snmpCreateOid(LEN_SQ_NET + 2, SQ_NET, 3, 3),
276 LEN_SQ_NET + 2, snmp_sysFn, 0))),
277 snmpAddNode(snmpCreateOid(LEN_SQ_MESH, SQ_MESH),
278 LEN_SQ_MESH, snmp_confFn, 2,
279 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 1, SQ_MESH, 1),
280 LEN_SQ_MESH + 1, snmp_sysFn, 1,
281 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 2, SQ_MESH, 1, 1),
282 LEN_SQ_MESH + 2, snmp_sysFn, 13,
283 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 1),
284 LEN_SQ_MESH + 3, snmp_sysFn, 0),
285 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 2),
286 LEN_SQ_MESH + 3, snmp_sysFn, 0),
287 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 3),
288 LEN_SQ_MESH + 3, snmp_sysFn, 0),
289 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 4),
290 LEN_SQ_MESH + 3, snmp_sysFn, 0),
291 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 5),
292 LEN_SQ_MESH + 3, snmp_sysFn, 0),
293 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 6),
294 LEN_SQ_MESH + 3, snmp_sysFn, 0),
295 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 7),
296 LEN_SQ_MESH + 3, snmp_sysFn, 0),
297 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 8),
298 LEN_SQ_MESH + 3, snmp_sysFn, 0),
299 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 9),
300 LEN_SQ_MESH + 3, snmp_sysFn, 0),
301 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 10),
302 LEN_SQ_MESH + 3, snmp_sysFn, 0),
303 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 11),
304 LEN_SQ_MESH + 3, snmp_sysFn, 0),
305 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 12),
306 LEN_SQ_MESH + 3, snmp_sysFn, 0),
307 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 13),
308 LEN_SQ_MESH + 3, snmp_sysFn, 0))),
309 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 1, SQ_MESH, 2),
310 LEN_SQ_MESH + 1, snmp_sysFn, 1,
311 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 2, SQ_MESH, 2, 1),
312 LEN_SQ_MESH + 2, snmp_sysFn, 9,
313 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 2, 1, 1),
314 LEN_SQ_MESH + 3, snmp_sysFn, 0),
315 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 2, 1, 2),
316 LEN_SQ_MESH + 3, snmp_sysFn, 0),
317 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 2, 1, 3),
318 LEN_SQ_MESH + 3, snmp_sysFn, 0),
319 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 2, 1, 4),
320 LEN_SQ_MESH + 3, snmp_sysFn, 0),
321 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 2, 1, 5),
322 LEN_SQ_MESH + 3, snmp_sysFn, 0),
323 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 2, 1, 6),
324 LEN_SQ_MESH + 3, snmp_sysFn, 0),
325 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 2, 1, 7),
326 LEN_SQ_MESH + 3, snmp_sysFn, 0),
327 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 2, 1, 8),
328 LEN_SQ_MESH + 3, snmp_sysFn, 0),
329 snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 2, 1, 9),
330 LEN_SQ_MESH + 3, snmp_sysFn, 0))))
331 )
332 )
333 )
334 )
335 )
336 )
337 )
338 );
339
340 debug(49, 9) ("snmpInit: Completed SNMP mib tree structure\n");
341 }
342
343 void
344 snmpConnectionOpen(void)
345 {
346 u_short port;
347 struct sockaddr_in xaddr;
348 socklen_t len;
349 int x;
350
351 debug(49, 5) ("snmpConnectionOpen: Called\n");
352 if ((port = Config.Port.snmp) > (u_short) 0) {
353 enter_suid();
354 theInSnmpConnection = comm_open(SOCK_DGRAM,
355 0,
356 Config.Addrs.snmp_incoming,
357 port,
358 COMM_NONBLOCKING,
359 "SNMP Port");
360 leave_suid();
361 if (theInSnmpConnection < 0)
362 fatal("Cannot open snmp Port");
363 commSetSelect(theInSnmpConnection, COMM_SELECT_READ, snmpHandleUdp, NULL, 0);
364 debug(1, 1) ("Accepting SNMP messages on port %d, FD %d.\n",
365 (int) port, theInSnmpConnection);
366 if (Config.Addrs.snmp_outgoing.s_addr != no_addr.s_addr) {
367 enter_suid();
368 theOutSnmpConnection = comm_open(SOCK_DGRAM,
369 0,
370 Config.Addrs.snmp_outgoing,
371 port,
372 COMM_NONBLOCKING,
373 "SNMP Port");
374 leave_suid();
375 if (theOutSnmpConnection < 0)
376 fatal("Cannot open Outgoing SNMP Port");
377 commSetSelect(theOutSnmpConnection,
378 COMM_SELECT_READ,
379 snmpHandleUdp,
380 NULL, 0);
381 debug(1, 1) ("Outgoing SNMP messages on port %d, FD %d.\n",
382 (int) port, theOutSnmpConnection);
383 fd_note(theOutSnmpConnection, "Outgoing SNMP socket");
384 fd_note(theInSnmpConnection, "Incoming SNMP socket");
385 } else {
386 theOutSnmpConnection = theInSnmpConnection;
387 }
388 memset(&theOutSNMPAddr, '\0', sizeof(struct in_addr));
389 len = sizeof(struct sockaddr_in);
390 memset(&xaddr, '\0', len);
391 x = getsockname(theOutSnmpConnection,
392 (struct sockaddr *) &xaddr, &len);
393 if (x < 0)
394 debug(51, 1) ("theOutSnmpConnection FD %d: getsockname: %s\n",
395 theOutSnmpConnection, xstrerror());
396 else
397 theOutSNMPAddr = xaddr.sin_addr;
398 }
399 }
400
401 void
402 snmpConnectionShutdown(void)
403 {
404 if (theInSnmpConnection < 0)
405 return;
406 if (theInSnmpConnection != theOutSnmpConnection) {
407 debug(49, 1) ("FD %d Closing SNMP socket\n", theInSnmpConnection);
408 comm_close(theInSnmpConnection);
409 }
410 /*
411 * Here we set 'theInSnmpConnection' to -1 even though the SNMP 'in'
412 * and 'out' sockets might be just one FD. This prevents this
413 * function from executing repeatedly. When we are really ready to
414 * exit or restart, main will comm_close the 'out' descriptor.
415 */ theInSnmpConnection = -1;
416 /*
417 * Normally we only write to the outgoing SNMP socket, but we
418 * also have a read handler there to catch messages sent to that
419 * specific interface. During shutdown, we must disable reading
420 * on the outgoing socket.
421 */
422 assert(theOutSnmpConnection > -1);
423 commSetSelect(theOutSnmpConnection, COMM_SELECT_READ, NULL, NULL, 0);
424 }
425
426 void
427 snmpConnectionClose(void)
428 {
429 snmpConnectionShutdown();
430 if (theOutSnmpConnection > -1) {
431 debug(49, 1) ("FD %d Closing SNMP socket\n", theOutSnmpConnection);
432 comm_close(theOutSnmpConnection);
433 }
434 }
435
436 /*
437 * Functions for handling the requests.
438 */
439
440 /*
441 * Accept the UDP packet
442 */
443 void
444 snmpHandleUdp(int sock, void *not_used)
445 {
446 LOCAL_ARRAY(char, buf, SNMP_REQUEST_SIZE);
447 struct sockaddr_in from;
448 socklen_t from_len;
449 snmp_request_t *snmp_rq;
450 int len;
451
452 debug(49, 5) ("snmpHandleUdp: Called.\n");
453
454 commSetSelect(sock, COMM_SELECT_READ, snmpHandleUdp, NULL, 0);
455 from_len = sizeof(struct sockaddr_in);
456 memset(&from, '\0', from_len);
457
458 Counter.syscalls.sock.recvfroms++;
459
460 len = recvfrom(sock,
461 buf,
462 SNMP_REQUEST_SIZE,
463 0,
464 (struct sockaddr *) &from,
465 &from_len);
466
467 if (len > 0) {
468 buf[len] = '\0';
469 debug(49, 3) ("snmpHandleUdp: FD %d: received %d bytes from %s.\n",
470 sock,
471 len,
472 inet_ntoa(from.sin_addr));
473
474 snmp_rq = xcalloc(1, sizeof(snmp_request_t));
475 snmp_rq->buf = (u_char *) buf;
476 snmp_rq->len = len;
477 snmp_rq->sock = sock;
478 snmp_rq->outbuf = xmalloc(snmp_rq->outlen = SNMP_REQUEST_SIZE);
479 memcpy(&snmp_rq->from, &from, sizeof(struct sockaddr_in));
480 snmpDecodePacket(snmp_rq);
481 } else {
482 debug(49, 1) ("snmpHandleUdp: FD %d recvfrom: %s\n", sock, xstrerror());
483 }
484 }
485
486 /*
487 * Turn SNMP packet into a PDU, check available ACL's
488 */
489 void
490 snmpDecodePacket(snmp_request_t * rq)
491 {
492 struct snmp_pdu *PDU;
493 struct snmp_session *Session;
494 aclCheck_t checklist;
495 u_char *Community;
496 u_char *buf = rq->buf;
497 int len = rq->len;
498 int allow = 0;
499
500 debug(49, 5) ("snmpDecodePacket: Called.\n");
501 /* Now that we have the data, turn it into a PDU */
502 Session = (struct snmp_session *) xmalloc(sizeof(struct snmp_session));
503 Session->Version = SNMP_VERSION_1;
504 Session->authenticator = NULL;
505 Session->community = (u_char *) xstrdup("public");
506 Session->community_len = 6;
507 cbdataAdd(rq, MEM_NONE);
508 PDU = snmp_pdu_create(0);
509 Community = snmp_parse(Session, PDU, buf, len);
510
511 checklist.src_addr = rq->from.sin_addr;
512 checklist.snmp_community = Community;
513
514 allow = aclCheckFast(Config.accessList.snmp, &checklist);
515 if ((snmp_coexist_V2toV1(PDU)) && (Community) && (allow)) {
516 rq->community = Community;
517 rq->PDU = PDU;
518 debug(49, 5) ("snmpAgentParse: reqid=[%d]\n", PDU->reqid);
519 snmpConstructReponse(rq, Session);
520 } else {
521 snmp_free_pdu(PDU);
522 }
523 }
524
525 /*
526 * Packet OK, ACL Check OK, Create reponse.
527 */
528 void
529 snmpConstructReponse(snmp_request_t * rq, struct snmp_session *Session)
530 {
531 struct snmp_pdu *RespPDU;
532 int ret;
533
534 debug(49, 5) ("snmpConstructReponse: Called.\n");
535
536 Session->community = rq->community;
537 Session->community_len = strlen((char *) rq->community);
538
539 RespPDU = snmpAgentResponse(rq->PDU);
540 snmp_free_pdu(rq->PDU);
541 xfree(Session);
542 if (RespPDU == NULL) {
543 } else {
544 ret = snmp_build(Session, RespPDU, rq->outbuf, &rq->outlen);
545 snmpUdpSend(rq->sock, &rq->from, rq->outbuf, rq->outlen);
546 snmp_free_pdu(RespPDU);
547 }
548 }
549
550 /*
551 * Decide how to respond to the request, construct a response and
552 * return the response to the requester.
553 *
554 * If configured forward any reponses which are not for this agent.
555 */
556 struct snmp_pdu *
557 snmpAgentResponse(struct snmp_pdu *PDU)
558 {
559 struct snmp_pdu *Answer = NULL;
560 oid_ParseFn *ParseFn = NULL;
561 variable_list *VarNew = NULL;
562
563 debug(49, 5) ("snmpAgentResponse: Called.\n");
564
565 if ((Answer = snmp_pdu_create(SNMP_PDU_RESPONSE))) {
566 Answer->reqid = PDU->reqid;
567 Answer->errindex = 0;
568 if (PDU->command == SNMP_PDU_GET) {
569
570 } else if (PDU->command == SNMP_PDU_GETNEXT) {
571 oid *NextOidName = NULL;
572 int NextOidNameLen = 0;
573
574 ParseFn = snmpTreeNext(PDU->variables->name, PDU->variables->name_length,
575 &(NextOidName), (snint *) & NextOidNameLen);
576
577 if (ParseFn == NULL) {
578 Answer->errstat = SNMP_ERR_NOSUCHNAME;
579 debug(49, 5) ("snmpAgentResponse: No such oid: ");
580 snmpDebugOid(5, PDU->variables->name, PDU->variables->name_length);
581 } else {
582 xfree(PDU->variables->name);
583 PDU->variables->name = NextOidName;
584 PDU->variables->name_length = NextOidNameLen;
585 VarNew = (*ParseFn) (PDU->variables, (snint *) & Answer->errstat);
586 }
587
588 /* Was there an error? */
589 if (Answer->errstat != SNMP_ERR_NOERROR) {
590 Answer->errindex = 1;
591
592 /* Just copy this variable */
593 Answer->variables = PDU->variables;
594 PDU->variables = NULL;
595 } else {
596 Answer->variables = VarNew;
597 }
598
599 } else {
600 snmp_free_pdu(Answer);
601 Answer = NULL;
602 }
603 }
604 return (Answer);
605 }
606
607 oid_ParseFn *
608 snmpTreeNext(oid * Current, snint CurrentLen, oid ** Next, snint * NextLen)
609 {
610 oid_ParseFn *Fn = NULL;
611 mib_tree_entry *mibTreeEntry = NULL, *new_oid = NULL;
612 int count = 0;
613
614 debug(49, 5) ("snmpTreeNext: Called\n");
615
616 debug(49, 6) ("snmpTreeNext: Current : \n");
617 snmpDebugOid(6, Current, CurrentLen);
618
619 mibTreeEntry = mib_tree_head;
620 if (Current[count] == mibTreeEntry->name[count]) {
621 count++;
622 while ((mibTreeEntry) && (count < CurrentLen)) {
623 mibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry);
624 count++;
625 }
626 debug(49, 5) ("snmpTreeNext: Past first\n");
627
628 if (mibTreeEntry->parsefunction) {
629 while (!new_oid) {
630 new_oid = snmpTreeEntry(Current[count] + 1, count, mibTreeEntry->parent);
631 if (!new_oid) {
632 mibTreeEntry = mibTreeEntry->parent;
633 count--;
634 }
635 }
636 }
637 debug(49, 5) ("snmpTreeNext: Past Second\n");
638
639 if ((!mibTreeEntry->parsefunction) && (mibTreeEntry)) {
640 while (!mibTreeEntry->parsefunction) {
641 mibTreeEntry = snmpTreeEntry(1, count, mibTreeEntry);
642 count++;
643 }
644 }
645 debug(49, 5) ("snmpTreeNext: Past Third\n");
646 }
647 if (mibTreeEntry) {
648 *Next = snmpOidDup(mibTreeEntry->name, mibTreeEntry->len);
649 *NextLen = mibTreeEntry->len;
650 Fn = mibTreeEntry->parsefunction;
651 }
652 debug(49, 5) ("snmpTreeNext: return\n");
653 return (Fn);
654 }
655
656 mib_tree_entry *
657 snmpTreeEntry(oid entry, snint len, mib_tree_entry * current)
658 {
659 mib_tree_entry *next = NULL;
660 int count = 0;
661
662 debug(49, 5) ("snmpTreeEntry: Called\n");
663
664 debug(49, 6) ("snmpTreeEntry: Oid: %d, Len: %d, Current : \n", entry, len);
665 snmpDebugOid(6, current->name, current->len);
666
667 while ((!next) && (count < current->children)) {
668 debug(49, 6) ("snmpTreeEntry: While loop count: %d, children: %d \n", count, current->children);
669 snmpDebugOid(6, current->leaves[count]->name, current->leaves[count]->len);
670 if (current->leaves[count]->name[len] == entry) {
671 next = current->leaves[count];
672 }
673 count++;
674 }
675 if (next) {
676 debug(49, 6) ("snmpTreeEntry: Returned : \n");
677 snmpDebugOid(6, next->name, next->len);
678 }
679 return (next);
680 }
681
682 /*
683 * Send the UDP reply.
684 */
685 void
686 snmpUdpSend(int fd, const struct sockaddr_in *to, void *msg, int len)
687 {
688 snmpUdpData *data = xcalloc(1, sizeof(snmpUdpData));
689 debug(49, 5) ("snmpUdpSend: Queueing response for %s\n",
690 inet_ntoa(to->sin_addr));
691 data->address = *to;
692 data->msg = msg;
693 data->len = len;
694 snmpAppendUdp(data);
695 commSetSelect(fd, COMM_SELECT_WRITE, snmpUdpReply, snmpUdpHead, 0);
696
697 }
698
699 void
700 snmpUdpReply(int fd, void *data)
701 {
702 snmpUdpData *queue = data;
703 int x;
704 /* Disable handler, in case of errors. */
705 commSetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0);
706 while ((queue = snmpUdpHead) != NULL) {
707 debug(49, 5) ("snmpUdpReply: FD %d sending %d bytes to %s port %d\n",
708 fd,
709 queue->len,
710 inet_ntoa(queue->address.sin_addr),
711 ntohs(queue->address.sin_port));
712 x = comm_udp_sendto(fd,
713 &queue->address,
714 sizeof(struct sockaddr_in),
715 queue->msg,
716 queue->len);
717 if (x < 0) {
718 if (ignoreErrno(errno))
719 break; /* don't de-queue */
720 }
721 snmpUdpHead = queue->next;
722 debug(49, 3) ("snmpUdpReply: freeing %p\n", queue->msg);
723 safe_free(queue->msg);
724 debug(49, 3) ("snmpUdpReply: freeing %p\n", queue);
725 safe_free(queue);
726 }
727 /* Reinstate handler if needed */
728 if (snmpUdpHead) {
729 commSetSelect(fd, COMM_SELECT_WRITE, snmpUdpReply, snmpUdpHead, 0);
730 }
731 }
732
733 void
734 snmpAppendUdp(snmpUdpData * item)
735 {
736 item->next = NULL;
737 if (snmpUdpHead == NULL) {
738 snmpUdpHead = item;
739 snmpUdpTail = item;
740 } else if (snmpUdpTail == snmpUdpHead) {
741 snmpUdpTail = item;
742 snmpUdpHead->next = item;
743 } else {
744 snmpUdpTail->next = item;
745 snmpUdpTail = item;
746 }
747
748 }
749
750 /*
751 * Utility functions
752 */
753
754 /*
755 * Tree utility functions.
756 */
757
758 /*
759 * Adds a node to the MIB tree structure and adds the appropriate children
760 */
761 mib_tree_entry *
762 snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, int children,...)
763 {
764 va_list args;
765 int loop;
766 mib_tree_entry *entry = NULL;
767
768 debug(49, 6) ("snmpAddNode: Children : %d, Oid : \n", children);
769 snmpDebugOid(6, name, len);
770
771 va_start(args, children);
772 entry = xmalloc(sizeof(mib_tree_entry));
773 entry->name = snmpOidDup(name, len);
774 entry->len = len;
775 entry->parsefunction = parsefunction;
776 entry->children = children;
777
778 if (children > 0) {
779 entry->leaves = xmalloc(sizeof(mib_tree_entry *) * children);
780 for (loop = 0; loop < children; loop++) {
781 entry->leaves[loop] = va_arg(args, mib_tree_entry *);
782 entry->leaves[loop]->parent = entry;
783 }
784 }
785 return (entry);
786 }
787 /* End of tree utility functions */
788
789 /*
790 * Returns the list of parameters in an oid[]
791 */
792 oid *
793 snmpCreateOid(int length,...)
794 {
795 va_list args;
796 oid *new_oid;
797 int loop;
798
799 va_start(args, length);
800 new_oid = xmalloc(sizeof(oid) * length);
801
802 if (length > 0) {
803 for (loop = 0; loop < length; loop++) {
804 new_oid[loop] = va_arg(args, int);
805 }
806 }
807 return (new_oid);
808 }
809
810 /*
811 * Allocate space for, and copy, an OID. Returns new oid, or NULL.
812 */
813 oid *
814 snmpOidDup(oid * A, snint ALen)
815 {
816 oid *Ans;
817
818 Ans = (oid *) xmalloc(sizeof(oid) * ALen);
819 if (Ans)
820 memcpy(Ans, A, (sizeof(oid) * ALen));
821 return (Ans);
822 }
823
824 /*
825 * Debug calls, prints out the OID for debugging purposes.
826 */
827 void
828 snmpDebugOid(int lvl, oid * Name, snint Len)
829 {
830 char mbuf[16], objid[1024];
831 int x;
832 objid[0] = '\0';
833
834 for (x = 0; x < Len; x++) {
835 snprintf(mbuf, sizeof(mbuf), ".%u", (unsigned int) Name[x]);
836 strncat(objid, mbuf, sizeof(objid));
837 }
838
839 debug(49, lvl) (" oid = %s\n", objid);
840 }
841
842 static void
843 snmpSnmplibDebug(int lvl, char *buf)
844 {
845 debug(49, lvl) ("%s", buf);
846 }