1 /* $Id: snmp.c,v 1.47 2005/10/12 03:04:38 jared Exp $ */
2 
3 #include "config.h"
4 
5 /* One of the many include files defines a 'clear' macro
6 which breaks the build on Mac OS X */
7 #undef clear
8 
9 /* SNMP specific includes */
10 #ifdef ENABLE_SNMP
11 
12 #ifdef HAVE_UCD_SNMP_VERSION_H
13 #include <ucd-snmp/ucd-snmp-config.h>
14 #include <ucd-snmp/ucd-snmp-includes.h>
15 #endif
16 
17 #ifdef HAVE_NET_SNMP_VERSION_H
18 #include <net-snmp/net-snmp-config.h>
19 #include <net-snmp/net-snmp-includes.h>
20 #include <net-snmp/library/snmp_client.h>
21 #endif
22 
23 
24 /* SNMP - The not so SIMPLE NETWORK MANAGMENT PROTOCOL */
25 
26 struct snmpdata {
27 	struct snmp_pdu *req;
28 	oid oid_value[MAX_OID_LEN];
29 	int oid_len;
30 	unsigned long snmp_retval;
31 	time_t snmp_response_time;
32 	bool snmp_response;
33 	struct snmp_session *sess;
34 };
35 #endif /* ENABLE_SNMP */
36 
37 int snmp_debug = 0;
38 
process_snmp_trap(int skt)39 void process_snmp_trap(int skt)
40 {
41 	/* Read the packet off the socket, read the src, process
42 	   the trap, etc.. */
43 
44 	/* For now, just log the raw packet dump via print_err(0,*) */
45 	char buffer[4096];
46 	int len;
47 /*	struct sockaddr from; */
48 	char from[16];
49 	int fromlen;
50 	struct in_addr foo;
51 
52 	len = recvfrom(skt, buffer, 4095, 0, (struct sockaddr*)from, &fromlen);
53 	memcpy(&foo, (from+4), 4);
54 	print_err(1, "caught a snmp trap from %s that was %d bytes", inet_ntoa(foo), len);
55 
56 	print_in_hex(buffer, len);
57 
58 	printf("\nfrom+fromlen\n");
59 	print_in_hex(from, fromlen);
60 
61 	if (len == -1)
62 	{
63 		perror("snmp.c:recvfrom");
64 	}
65 
66 #ifdef FOO
67 	print_err(1, "received a packet from %s of length %d",
68 		inet_ntoa((struct in_addr*)from), fromlen);
69 #endif /* FOO */
70 }
71 
72 #ifdef ENABLE_SNMP
73 
74 /*
75  * extract the data from the snmp packet
76  */
extract_snmp_result(int status,struct snmp_session * sp,struct snmp_pdu * pdu,struct snmpdata * snmp_nfo)77 int extract_snmp_result (int status, struct snmp_session *sp,
78 	struct snmp_pdu *pdu, struct snmpdata *snmp_nfo)
79 {
80   struct variable_list *vp;
81   int ix;
82 
83 /*
84 (gdb) print *pdu->variables->val->counter64
85 $6 = {high = 0, low = 1854873}
86 
87   eg: pdu->variables->val->counter64.low
88  */
89 
90 #warning need to correctly differentiate btw 32 and 64 bit responses
91 
92   switch (status)
93   {
94    case STAT_SUCCESS:
95    {
96     vp = pdu->variables;
97     if (pdu->errstat == SNMP_ERR_NOERROR)
98     {
99       if (vp->val.integer)
100       {
101         snmp_nfo->snmp_retval = (unsigned long)(*vp->val.integer);
102         if ((snmp_nfo->snmp_retval == 0) &&
103           (vp->val.counter64->low != 0))
104 		snmp_nfo->snmp_retval = (unsigned long)(vp->val.counter64->low);
105         snmp_nfo->snmp_response = TRUE;
106         time(&snmp_nfo->snmp_response_time);
107       }
108     } else {
109       for (ix = 1; vp && ix != pdu->errindex; vp = vp->next_variable, ix++);
110       if (vp != NULL)
111       {
112         if (vp->val.integer)
113         {
114           snmp_nfo->snmp_retval = (unsigned long)(*vp->val.integer);
115         if ((snmp_nfo->snmp_retval == 0) &&
116           (vp->val.counter64->low != 0))
117                 snmp_nfo->snmp_retval = (unsigned long)(vp->val.counter64->low);
118           snmp_nfo->snmp_response = TRUE;
119           time(&snmp_nfo->snmp_response_time);
120         }
121       }
122     }
123     return 1;
124    }
125    case STAT_TIMEOUT:
126    {
127     return -1;
128    }
129 
130   }
131   return 0;
132 }
133 
134 
snmp_callback_response(int operation,struct snmp_session * sp,int reqid,struct snmp_pdu * pdu,void * magic)135 int snmp_callback_response(int operation, struct snmp_session *sp, int reqid,
136                     struct snmp_pdu *pdu, void *magic)
137 {
138 	struct monitorent *here = (struct monitorent *)magic;
139 	struct snmpdata *localstruct;
140 
141 	if (debug|snmp_debug)
142 	{
143         	print_err(1, "snmp.c:inside snmp_callback_response %x",
144 			here->monitordata);
145 	}
146 
147 	localstruct = here->monitordata;
148 
149 #ifndef RECEIVED_MESSAGE
150 #define RECEIVED_MESSAGE NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE
151 #endif /* RECEIVED_MESSAGE */
152 	if (operation == RECEIVED_MESSAGE)
153 	{
154 		if (extract_snmp_result(STAT_SUCCESS, localstruct->sess, pdu, localstruct))
155 		{
156 			if (debug|snmp_debug)
157 				print_err(1, "snmp.c:snmp_callback_response:snmp_retval = %d on %s", localstruct->snmp_retval, here->checkent->hostname);
158 			return 1;
159 		}
160 	}
161 
162 	here->retval = SYSM_NORESP;
163 
164 	return 0;
165 }
166 
167 /*
168  * start snmp query
169  */
start_test_snmp(struct monitorent * here)170 void start_test_snmp(struct monitorent *here)
171 {
172 	struct snmpdata *localstruct;
173         struct snmp_session startup_sess;
174 
175 	localstruct = MALLOC(sizeof(struct snmpdata), "snmpdata");
176 
177 	here->monitordata = localstruct;
178 
179 	localstruct->snmp_retval = 0;
180 	localstruct->snmp_response = FALSE;
181 
182 	snmp_sess_init(&startup_sess);	/* initialize session */
183 
184 	startup_sess.version = SNMP_VERSION_2c;
185 	startup_sess.peername = here->checkent->hostname;
186 	startup_sess.community = here->checkent->snmp_community;
187 
188         startup_sess.remote_port = SNMP_DEFAULT_REMPORT;
189         startup_sess.timeout = SNMP_DEFAULT_TIMEOUT;
190         startup_sess.retries = SNMP_DEFAULT_RETRIES;
191 
192 	startup_sess.community_len =strlen(here->checkent->snmp_community);
193 
194 	/* set function to get callback data */
195 	startup_sess.callback = snmp_callback_response;
196 	startup_sess.callback_magic = here;
197 
198 	/* call snmp_open */
199 
200 	localstruct->sess = snmp_open(&startup_sess);
201 
202 	if (localstruct->sess == NULL)
203 	{
204 		print_err(1, "snmp_open returned an error");
205 		/* return an error */
206 		here->retval = -2;
207 		return;
208 	}
209 
210 	/* create pdu */
211 
212 	localstruct->req = snmp_pdu_create(SNMP_MSG_GET);
213 
214 	memset(localstruct->oid_value, 0, MAX_OID_LEN);
215 
216 	localstruct->oid_len = sizeof(localstruct->oid_value);
217 
218 	if (!read_objid(here->checkent->snmp_oid, localstruct->oid_value,
219 		&localstruct->oid_len))
220 	{
221 		snmp_perror("snmp.c:read_objid");
222 		here->retval = -2;
223 		return;
224 	}
225 
226 	snmp_add_null_var(localstruct->req,
227 		localstruct->oid_value,
228 		localstruct->oid_len);
229 
230 	/* send snmp packet */
231         if (debug|snmp_debug) print_err(1, "calling snmp_send");
232 
233 	/* snmp_send returns 0 on error, 1 on success */
234 	if (snmp_send(localstruct->sess, localstruct->req) == 0)
235 	{
236 		perror("snmp_send");
237 	}
238 
239 	return;
240 }
241 
stop_test_snmp(struct monitorent * here)242 void stop_test_snmp(struct monitorent *here)
243 {
244 	struct snmpdata *localstruct = NULL;
245 
246 	localstruct = here->monitordata;
247         if (localstruct == NULL)
248         {
249                 print_err(1, "snmp.c:stop_test_snmp localstruct is null");
250                 return;
251         }
252 
253 	/* close the snmp socket */
254 	snmp_close(localstruct->sess);
255 
256         free(localstruct);
257         here->monitordata = NULL;
258 
259 	return;
260 }
261 
service_test_snmp(struct monitorent * here)262 void service_test_snmp(struct monitorent *here)
263 {
264 	struct snmpdata *localstruct = NULL;
265 	fd_set fdset;
266 	int max_fd = 0;
267 	int block = 1;
268 	int ret = 0;
269 	unsigned long rate_time;
270 	unsigned long rate_time_val;
271 	unsigned long rate_avg_val;
272 	struct timeval timeout;
273         struct timeval now;
274 
275 	localstruct = here->monitordata;
276 	if (localstruct == NULL)
277 	{
278 		print_err(1, "snmp.c:service_test_snmp localstruct is null");
279 		return;
280 	}
281 
282 	FD_ZERO(&fdset);
283 	snmp_select_info(&max_fd, &fdset, &timeout, &block);
284 
285         timeout.tv_sec = 0;
286         timeout.tv_usec = 0;
287 
288 	ret = select(max_fd, &fdset, NULL, NULL, &timeout);
289 	if (ret)
290 	{
291 		snmp_read(&fdset);
292 	}
293 
294 	if (debug|snmp_debug) print_err(1, "snmp.c:svc_test_snmp:snmp_response = %d", localstruct->snmp_response);
295 	if (localstruct->snmp_response)
296 	{
297 		if (debug|snmp_debug) print_err(1, "snmp.c:snmp_response(%s)", here->checkent->hostname);
298 		switch (here->checkent->snmp_test_type)
299 		{
300 			case SYSM_SNMP_TYPE_REBOOT:
301 				if (debug|snmp_debug) print_err(1, "snmp.c:type_reboot:comparing last(%d) > now(%d)", here->checkent->system_uptime, localstruct->snmp_retval);
302 				if (here->checkent->system_uptime > localstruct->snmp_retval)
303 				{
304 					here->retval = SYSM_SNMP_REBOOT;
305 				} else {
306 					here->retval = SYSM_OK;
307 				}
308 				here->checkent->system_uptime = localstruct->snmp_retval;
309 				break;
310 			case SYSM_SNMP_TYPE_HIGH:
311 				if (debug|snmp_debug) print_err(1, "snmp.c:type_high:comparing received value %d with configured %d", localstruct->snmp_retval, here->checkent->snmp_high);
312 				if (here->checkent->snmp_high < localstruct->snmp_retval)
313 				{
314 					here->retval = SYSM_SNMP_HIGH;
315 				} else {
316 					here->retval = SYSM_OK;
317 				}
318 				/* stash last snmp value */
319                                 here->checkent->system_uptime = localstruct->snmp_retval;
320 				break;
321 			case SYSM_SNMP_TYPE_LOW:
322 				if (debug|snmp_debug) print_err(1, "snmp.c:type_low:comparing received value %d with configured %d", localstruct->snmp_retval, here->checkent->snmp_low);
323 				if (here->checkent->snmp_low > localstruct->snmp_retval)
324 				{
325 					here->retval = SYSM_SNMP_LOW;
326 				} else {
327 					here->retval = SYSM_OK;
328 				}
329 				/* stash last snmp value */
330                                 here->checkent->system_uptime = localstruct->snmp_retval;
331 				break;
332 			case SYSM_SNMP_TYPE_RANGE:
333 				if ((here->checkent->snmp_low < localstruct->snmp_retval) && (here->checkent->snmp_high > localstruct->snmp_retval))
334 				{
335 					here->retval = SYSM_SNMP_OOR;
336 				} else {
337 					here->retval = SYSM_OK;
338 				}
339 				/* stash last snmp value */
340                                 here->checkent->system_uptime = localstruct->snmp_retval;
341 				break;
342 			case SYSM_SNMP_TYPE_EXACT:
343 				if (here->checkent->snmp_exact != localstruct->snmp_retval)
344 				{
345 					here->retval = SYSM_SNMP_NOTEXACT;
346 				} else {
347 					here->retval = SYSM_OK;
348 				}
349 				/* stash last snmp value */
350 				here->checkent->system_uptime = localstruct->snmp_retval;
351 				break;
352 			case SYSM_SNMP_TYPE_COMPARE:
353 				break;
354 			case SYSM_SNMP_TYPE_RATE:
355 				rate_time = (localstruct->snmp_response_time - here->checkent->last_snmp_resptime);
356 				rate_time_val = (localstruct->snmp_retval - here->checkent->system_uptime);
357 				if (here->checkent->snmp_octets)
358 				{
359 					rate_avg_val=(rate_time_val*8/rate_time);
360 				} else {
361 					rate_avg_val=(rate_time_val/rate_time);
362 				}
363 
364 				if (debug|snmp_debug)
365 					print_err(1, "snmp.c:rate_avg_val = %u ; here->checkent->snmp_rate %u", rate_avg_val, here->checkent->snmp_rate);
366 				here->checkent->system_uptime = localstruct->snmp_retval;
367 				here->checkent->last_snmp_resptime = localstruct->snmp_response_time;
368 				if (rate_avg_val > here->checkent->snmp_rate)
369 				{
370 					here->retval = SYSM_SNMP_HIGHRATE;
371 				} else {
372 					here->retval = SYSM_OK;
373 				}
374 				break;
375 			default:
376 				print_err(1, "snmp.c:invalid snmp type");
377 				here->retval = -2;
378 				break;
379 		}
380 
381 	} else {
382 	        gettimeofday(&now, NULL); /* get the current time */
383 		if (mydifftime(here->queueat, now) >= 30)
384 		{
385 			here->retval = SYSM_NORESP;
386 		}
387 	}
388 
389 	if (debug|snmp_debug)
390 	{
391 		print_err(1, "snmp.c:svc_test_snmp:checking here->retval it is %d", here->retval);
392 	}
393 
394 	if (here->retval != -1)
395 	{
396 		if (debug|snmp_debug) print_err(1, "snmp.c:svc_test_snmp:here->retval = %d", here->retval);
397                 snmp_close(localstruct->sess);
398 
399                 free(here->monitordata);
400 
401                 here->monitordata = NULL;
402 	}
403 
404 	return;
405 }
406 #endif /* ENABLE_SNMP */
407