d79da8cf7cbc6bd94d3f4c8c032d0874dfc43b56
1 /*****************************************************************************
2 *
3 * Nagios check_snmp plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2007 Nagios Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains the check_snmp plugin
11 *
12 * Check status of remote machines and obtain system information via SNMP
13 *
14 *
15 * This program is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 *
28 *
29 *****************************************************************************/
31 const char *progname = "check_snmp";
32 const char *copyright = "1999-2007";
33 const char *email = "nagiosplug-devel@lists.sourceforge.net";
35 #include "common.h"
36 #include "utils.h"
37 #include "utils_cmd.h"
39 #define DEFAULT_COMMUNITY "public"
40 #define DEFAULT_PORT "161"
41 #define DEFAULT_MIBLIST "ALL"
42 #define DEFAULT_PROTOCOL "1"
43 #define DEFAULT_TIMEOUT 1
44 #define DEFAULT_RETRIES 5
45 #define DEFAULT_AUTH_PROTOCOL "MD5"
46 #define DEFAULT_PRIV_PROTOCOL "DES"
47 #define DEFAULT_DELIMITER "="
48 #define DEFAULT_OUTPUT_DELIMITER " "
50 #define mark(a) ((a)!=0?"*":"")
52 #define CHECK_UNDEF 0
53 #define CRIT_PRESENT 1
54 #define CRIT_STRING 2
55 #define CRIT_REGEX 4
56 #define WARN_PRESENT 8
57 #define WARN_STRING 16
58 #define WARN_REGEX 32
60 #define MAX_OIDS 8
62 /* Longopts only arguments */
63 #define L_CALCULATE_RATE CHAR_MAX+1
64 #define L_RATE_MULTIPLIER CHAR_MAX+2
65 #define L_INVERT_SEARCH CHAR_MAX+3
67 /* Gobble to string - stop incrementing c when c[0] match one of the
68 * characters in s */
69 #define GOBBLE_TOS(c, s) while(c[0]!='\0' && strchr(s, c[0])==NULL) { c++; }
70 /* Given c, keep track of backslashes (bk) and double-quotes (dq)
71 * from c[0] */
72 #define COUNT_SEQ(c, bk, dq) switch(c[0]) {\
73 case '\\': \
74 if (bk) bk--; \
75 else bk++; \
76 break; \
77 case '"': \
78 if (!dq) { dq++; } \
79 else if(!bk) { dq--; } \
80 else { bk--; } \
81 break; \
82 }
86 int process_arguments (int, char **);
87 int validate_arguments (void);
88 char *thisarg (char *str);
89 char *nextarg (char *str);
90 void print_usage (void);
91 void print_help (void);
93 #include "regex.h"
94 char regex_expect[MAX_INPUT_BUFFER] = "";
95 regex_t preg;
96 regmatch_t pmatch[10];
97 char errbuf[MAX_INPUT_BUFFER] = "";
98 char perfstr[MAX_INPUT_BUFFER] = "| ";
99 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
100 int eflags = 0;
101 int errcode, excode;
103 char *server_address = NULL;
104 char *community = NULL;
105 char **authpriv = NULL;
106 char *proto = NULL;
107 char *seclevel = NULL;
108 char *secname = NULL;
109 char *authproto = NULL;
110 char *privproto = NULL;
111 char *authpasswd = NULL;
112 char *privpasswd = NULL;
113 char **oids = NULL;
114 char *label;
115 char *units;
116 char *port;
117 char *snmpcmd;
118 char string_value[MAX_INPUT_BUFFER] = "";
119 int invert_search=0;
120 char **labels = NULL;
121 char **unitv = NULL;
122 size_t nlabels = 0;
123 size_t labels_size = 8;
124 size_t nunits = 0;
125 size_t unitv_size = 8;
126 int numoids = 0;
127 int numauthpriv = 0;
128 int verbose = 0;
129 int usesnmpgetnext = FALSE;
130 char *warning_thresholds = NULL;
131 char *critical_thresholds = NULL;
132 thresholds *thlds[MAX_OIDS];
133 double response_value[MAX_OIDS];
134 int retries = 0;
135 int eval_method[MAX_OIDS];
136 char *delimiter;
137 char *output_delim;
138 char *miblist = NULL;
139 int needmibs = FALSE;
140 int calculate_rate = 0;
141 int rate_multiplier = 1;
142 state_data *previous_state;
143 double previous_value[MAX_OIDS];
146 int
147 main (int argc, char **argv)
148 {
149 int i, len, line, total_oids;
150 unsigned int bk_count = 0, dq_count = 0;
151 int iresult = STATE_UNKNOWN;
152 int result = STATE_UNKNOWN;
153 int return_code = 0;
154 int external_error = 0;
155 char **command_line = NULL;
156 char *cl_hidden_auth = NULL;
157 char *oidname = NULL;
158 char *response = NULL;
159 char *mult_resp = NULL;
160 char *outbuff;
161 char *ptr = NULL;
162 char *show = NULL;
163 char *th_warn=NULL;
164 char *th_crit=NULL;
165 char type[8] = "";
166 output chld_out, chld_err;
167 char *previous_string=NULL;
168 char *ap=NULL;
169 char *state_string=NULL;
170 size_t response_length, current_length, string_length;
171 char *temp_string=NULL;
172 time_t current_time;
173 double temp_double;
174 time_t duration;
175 char *conv = "12345678";
176 int is_counter=0;
178 setlocale (LC_ALL, "");
179 bindtextdomain (PACKAGE, LOCALEDIR);
180 textdomain (PACKAGE);
182 labels = malloc (labels_size);
183 unitv = malloc (unitv_size);
184 for (i = 0; i < MAX_OIDS; i++)
185 eval_method[i] = CHECK_UNDEF;
187 label = strdup ("SNMP");
188 units = strdup ("");
189 port = strdup (DEFAULT_PORT);
190 outbuff = strdup ("");
191 delimiter = strdup (" = ");
192 output_delim = strdup (DEFAULT_OUTPUT_DELIMITER);
193 timeout_interval = DEFAULT_TIMEOUT;
194 retries = DEFAULT_RETRIES;
196 np_init( (char *) progname, argc, argv );
198 /* Parse extra opts if any */
199 argv=np_extra_opts (&argc, argv, progname);
201 np_set_args(argc, argv);
203 if (process_arguments (argc, argv) == ERROR)
204 usage4 (_("Could not parse arguments"));
206 if(calculate_rate) {
207 if (!strcmp(label, "SNMP"))
208 label = strdup("SNMP RATE");
209 time(¤t_time);
210 i=0;
211 previous_state = np_state_read();
212 if(previous_state!=NULL) {
213 /* Split colon separated values */
214 previous_string = strdup((char *) previous_state->data);
215 while((ap = strsep(&previous_string, ":")) != NULL) {
216 if(verbose>2)
217 printf("State for %d=%s\n", i, ap);
218 previous_value[i++]=strtod(ap,NULL);
219 }
220 }
221 }
223 /* Populate the thresholds */
224 th_warn=warning_thresholds;
225 th_crit=critical_thresholds;
226 for (i=0; i<numoids; i++) {
227 char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL;
228 char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL;
229 /* Skip empty thresholds, while avoiding segfault */
230 set_thresholds(&thlds[i],
231 w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL,
232 c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL);
233 if (w) {
234 th_warn=strchr(th_warn, ',');
235 if (th_warn) th_warn++;
236 free(w);
237 }
238 if (c) {
239 th_crit=strchr(th_crit, ',');
240 if (th_crit) th_crit++;
241 free(c);
242 }
243 }
245 /* Create the command array to execute */
246 if(usesnmpgetnext == TRUE) {
247 snmpcmd = strdup (PATH_TO_SNMPGETNEXT);
248 }else{
249 snmpcmd = strdup (PATH_TO_SNMPGET);
250 }
252 /* 9 arguments to pass before authpriv options + 1 for host and numoids. Add one for terminating NULL */
253 command_line = calloc (9 + numauthpriv + 1 + numoids + 1, sizeof (char *));
254 command_line[0] = snmpcmd;
255 command_line[1] = strdup ("-t");
256 asprintf (&command_line[2], "%d", timeout_interval);
257 command_line[3] = strdup ("-r");
258 asprintf (&command_line[4], "%d", retries);
259 command_line[5] = strdup ("-m");
260 command_line[6] = strdup (miblist);
261 command_line[7] = "-v";
262 command_line[8] = strdup (proto);
264 for (i = 0; i < numauthpriv; i++) {
265 command_line[9 + i] = authpriv[i];
266 }
268 asprintf (&command_line[9 + numauthpriv], "%s:%s", server_address, port);
270 /* This is just for display purposes, so it can remain a string */
271 asprintf(&cl_hidden_auth, "%s -t %d -r %d -m %s -v %s %s %s:%s",
272 snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''", proto, "[authpriv]",
273 server_address, port);
275 for (i = 0; i < numoids; i++) {
276 command_line[9 + numauthpriv + 1 + i] = oids[i];
277 asprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]);
278 }
280 command_line[9 + numauthpriv + 1 + numoids] = NULL;
282 if (verbose)
283 printf ("%s\n", cl_hidden_auth);
285 /* Run the command */
286 return_code = cmd_run_array (command_line, &chld_out, &chld_err, 0);
288 /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs,
289 only return state unknown if return code is non zero or there is no stdout.
290 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
291 */
292 if (return_code != 0)
293 external_error=1;
294 if (chld_out.lines == 0)
295 external_error=1;
296 if (external_error) {
297 if (chld_err.lines > 0) {
298 printf (_("External command error: %s\n"), chld_err.line[0]);
299 for (i = 1; i < chld_err.lines; i++) {
300 printf ("%s\n", chld_err.line[i]);
301 }
302 } else {
303 printf(_("External command error with no output (return code: %d)\n"), return_code);
304 }
305 exit (STATE_UNKNOWN);
306 }
308 if (verbose) {
309 for (i = 0; i < chld_out.lines; i++) {
310 printf ("%s\n", chld_out.line[i]);
311 }
312 }
314 for (line=0, i=0; line < chld_out.lines; line++, i++) {
315 if(calculate_rate)
316 conv = "%.10g";
317 else
318 conv = "%.0f";
320 ptr = chld_out.line[line];
321 oidname = strpcpy (oidname, ptr, delimiter);
322 response = strstr (ptr, delimiter);
323 if (response == NULL)
324 break;
326 if (verbose > 2) {
327 printf("Processing oid %i (line %i)\n oidname: %s\n response: %s\n", i+1, line+1, oidname, response);
328 }
330 /* Clean up type array - Sol10 does not necessarily zero it out */
331 bzero(type, sizeof(type));
333 is_counter=0;
334 /* We strip out the datatype indicator for PHBs */
335 if (strstr (response, "Gauge: ")) {
336 show = strstr (response, "Gauge: ") + 7;
337 }
338 else if (strstr (response, "Gauge32: ")) {
339 show = strstr (response, "Gauge32: ") + 9;
340 }
341 else if (strstr (response, "Counter32: ")) {
342 show = strstr (response, "Counter32: ") + 11;
343 is_counter=1;
344 if(!calculate_rate)
345 strcpy(type, "c");
346 }
347 else if (strstr (response, "Counter64: ")) {
348 show = strstr (response, "Counter64: ") + 11;
349 is_counter=1;
350 if(!calculate_rate)
351 strcpy(type, "c");
352 }
353 else if (strstr (response, "INTEGER: ")) {
354 show = strstr (response, "INTEGER: ") + 9;
355 }
356 else if (strstr (response, "STRING: ")) {
357 show = strstr (response, "STRING: ") + 8;
358 conv = "%.10g";
360 /* Get the rest of the string on multi-line strings */
361 ptr = show;
362 COUNT_SEQ(ptr, bk_count, dq_count)
363 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
364 ptr++;
365 GOBBLE_TOS(ptr, "\n\"\\")
366 COUNT_SEQ(ptr, bk_count, dq_count)
367 }
369 if (dq_count) { /* unfinished line */
370 /* copy show verbatim first */
371 if (!mult_resp) mult_resp = strdup("");
372 asprintf (&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show);
373 /* then strip out unmatched double-quote from single-line output */
374 if (show[0] == '"') show++;
376 /* Keep reading until we match end of double-quoted string */
377 for (line++; line < chld_out.lines; line++) {
378 ptr = chld_out.line[line];
379 asprintf (&mult_resp, "%s%s\n", mult_resp, ptr);
381 COUNT_SEQ(ptr, bk_count, dq_count)
382 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
383 ptr++;
384 GOBBLE_TOS(ptr, "\n\"\\")
385 COUNT_SEQ(ptr, bk_count, dq_count)
386 }
387 /* Break for loop before next line increment when done */
388 if (!dq_count) break;
389 }
390 }
392 }
393 else if (strstr (response, "Timeticks: ")) {
394 show = strstr (response, "Timeticks: ");
395 }
396 else
397 show = response;
399 iresult = STATE_DEPENDENT;
401 /* Process this block for numeric comparisons */
402 /* Make some special values,like Timeticks numeric only if a threshold is defined */
403 if (thlds[i]->warning || thlds[i]->critical || calculate_rate) {
404 ptr = strpbrk (show, "0123456789");
405 if (ptr == NULL)
406 die (STATE_UNKNOWN,_("No valid data returned"));
407 response_value[i] = strtod (ptr, NULL);
409 if(calculate_rate) {
410 if (previous_state!=NULL) {
411 duration = current_time-previous_state->time;
412 if(duration<=0)
413 die(STATE_UNKNOWN,_("Time duration between plugin calls is invalid"));
414 temp_double = response_value[i]-previous_value[i];
415 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
416 if(is_counter) {
417 if(temp_double<(double)0.0)
418 temp_double+=(double)4294967296.0; /* 2^32 */
419 if(temp_double<(double)0.0)
420 temp_double+=(double)18446744069414584320.0; /* 2^64-2^32 */;
421 }
422 /* Convert to per second, then use multiplier */
423 temp_double = temp_double/duration*rate_multiplier;
424 iresult = get_status(temp_double, thlds[i]);
425 asprintf (&show, conv, temp_double);
426 }
427 } else {
428 iresult = get_status(response_value[i], thlds[i]);
429 asprintf (&show, conv, response_value[i]);
430 }
431 }
433 /* Process this block for string matching */
434 else if (eval_method[i] & CRIT_STRING) {
435 if (strcmp (show, string_value))
436 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
437 else
438 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
439 }
441 /* Process this block for regex matching */
442 else if (eval_method[i] & CRIT_REGEX) {
443 excode = regexec (&preg, response, 10, pmatch, eflags);
444 if (excode == 0) {
445 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
446 }
447 else if (excode != REG_NOMATCH) {
448 regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER);
449 printf (_("Execute Error: %s\n"), errbuf);
450 exit (STATE_CRITICAL);
451 }
452 else {
453 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
454 }
455 }
457 /* Process this block for existence-nonexistence checks */
458 /* TV: Should this be outside of this else block? */
459 else {
460 if (eval_method[i] & CRIT_PRESENT)
461 iresult = STATE_CRITICAL;
462 else if (eval_method[i] & WARN_PRESENT)
463 iresult = STATE_WARNING;
464 else if (response && iresult == STATE_DEPENDENT)
465 iresult = STATE_OK;
466 }
468 /* Result is the worst outcome of all the OIDs tested */
469 result = max_state (result, iresult);
471 /* Prepend a label for this OID if there is one */
472 if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
473 asprintf (&outbuff, "%s%s%s %s%s%s", outbuff,
474 (i == 0) ? " " : output_delim,
475 labels[i], mark (iresult), show, mark (iresult));
476 else
477 asprintf (&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim,
478 mark (iresult), show, mark (iresult));
480 /* Append a unit string for this OID if there is one */
481 if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL)
482 asprintf (&outbuff, "%s %s", outbuff, unitv[i]);
484 /* Write perfdata with whatever can be parsed by strtod, if possible */
485 ptr = NULL;
486 strtod(show, &ptr);
487 if (ptr > show) {
488 if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
489 temp_string=labels[i];
490 else
491 temp_string=oidname;
492 strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1);
493 strncat(perfstr, "=", sizeof(perfstr)-strlen(perfstr)-1);
494 len = sizeof(perfstr)-strlen(perfstr)-1;
495 strncat(perfstr, show, len>ptr-show ? ptr-show : len);
497 if (type)
498 strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1);
499 strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1);
500 }
501 }
502 total_oids=i;
504 /* Save state data, as all data collected now */
505 if(calculate_rate) {
506 string_length=1024;
507 state_string=malloc(string_length);
508 if(state_string==NULL)
509 die(STATE_UNKNOWN, _("Cannot malloc"));
511 current_length=0;
512 for(i=0; i<total_oids; i++) {
513 asprintf(&temp_string,"%.0f",response_value[i]);
514 if(temp_string==NULL)
515 die(STATE_UNKNOWN,_("Cannot asprintf()"));
516 response_length = strlen(temp_string);
517 if(current_length+response_length>string_length) {
518 string_length=current_length+1024;
519 state_string=realloc(state_string,string_length);
520 if(state_string==NULL)
521 die(STATE_UNKNOWN, _("Cannot realloc()"));
522 }
523 strcpy(&state_string[current_length],temp_string);
524 current_length=current_length+response_length;
525 state_string[current_length]=':';
526 current_length++;
527 free(temp_string);
528 }
529 state_string[--current_length]='\0';
530 if (verbose > 2)
531 printf("State string=%s\n",state_string);
533 /* This is not strictly the same as time now, but any subtle variations will cancel out */
534 np_state_write_string(current_time, state_string );
535 if(previous_state==NULL) {
536 /* Or should this be highest state? */
537 die( STATE_OK, _("No previous data to calculate rate - assume okay" ) );
538 }
539 }
541 printf ("%s %s -%s %s\n", label, state_text (result), outbuff, perfstr);
542 if (mult_resp) printf ("%s", mult_resp);
544 return result;
545 }
549 /* process command-line arguments */
550 int
551 process_arguments (int argc, char **argv)
552 {
553 char *ptr;
554 int c = 1;
555 int j = 0, jj = 0, ii = 0;
557 int option = 0;
558 static struct option longopts[] = {
559 STD_LONG_OPTS,
560 {"community", required_argument, 0, 'C'},
561 {"oid", required_argument, 0, 'o'},
562 {"object", required_argument, 0, 'o'},
563 {"delimiter", required_argument, 0, 'd'},
564 {"output-delimiter", required_argument, 0, 'D'},
565 {"string", required_argument, 0, 's'},
566 {"timeout", required_argument, 0, 't'},
567 {"regex", required_argument, 0, 'r'},
568 {"ereg", required_argument, 0, 'r'},
569 {"eregi", required_argument, 0, 'R'},
570 {"label", required_argument, 0, 'l'},
571 {"units", required_argument, 0, 'u'},
572 {"port", required_argument, 0, 'p'},
573 {"retries", required_argument, 0, 'e'},
574 {"miblist", required_argument, 0, 'm'},
575 {"protocol", required_argument, 0, 'P'},
576 {"seclevel", required_argument, 0, 'L'},
577 {"secname", required_argument, 0, 'U'},
578 {"authproto", required_argument, 0, 'a'},
579 {"privproto", required_argument, 0, 'x'},
580 {"authpasswd", required_argument, 0, 'A'},
581 {"privpasswd", required_argument, 0, 'X'},
582 {"next", no_argument, 0, 'n'},
583 {"rate", no_argument, 0, L_CALCULATE_RATE},
584 {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER},
585 {"invert-search", no_argument, 0, L_INVERT_SEARCH},
586 {0, 0, 0, 0}
587 };
589 if (argc < 2)
590 return ERROR;
592 /* reverse compatibility for very old non-POSIX usage forms */
593 for (c = 1; c < argc; c++) {
594 if (strcmp ("-to", argv[c]) == 0)
595 strcpy (argv[c], "-t");
596 if (strcmp ("-wv", argv[c]) == 0)
597 strcpy (argv[c], "-w");
598 if (strcmp ("-cv", argv[c]) == 0)
599 strcpy (argv[c], "-c");
600 }
602 while (1) {
603 c = getopt_long (argc, argv, "nhvVt:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:L:U:a:x:A:X:",
604 longopts, &option);
606 if (c == -1 || c == EOF)
607 break;
609 switch (c) {
610 case '?': /* usage */
611 usage5 ();
612 case 'h': /* help */
613 print_help ();
614 exit (STATE_OK);
615 case 'V': /* version */
616 print_revision (progname, NP_VERSION);
617 exit (STATE_OK);
618 case 'v': /* verbose */
619 verbose++;
620 break;
622 /* Connection info */
623 case 'C': /* group or community */
624 community = optarg;
625 break;
626 case 'H': /* Host or server */
627 server_address = optarg;
628 break;
629 case 'p': /* TCP port number */
630 port = optarg;
631 break;
632 case 'm': /* List of MIBS */
633 miblist = optarg;
634 break;
635 case 'n': /* usesnmpgetnext */
636 usesnmpgetnext = TRUE;
637 break;
638 case 'P': /* SNMP protocol version */
639 proto = optarg;
640 break;
641 case 'L': /* security level */
642 seclevel = optarg;
643 break;
644 case 'U': /* security username */
645 secname = optarg;
646 break;
647 case 'a': /* auth protocol */
648 authproto = optarg;
649 break;
650 case 'x': /* priv protocol */
651 privproto = optarg;
652 break;
653 case 'A': /* auth passwd */
654 authpasswd = optarg;
655 break;
656 case 'X': /* priv passwd */
657 privpasswd = optarg;
658 break;
659 case 't': /* timeout period */
660 if (!is_integer (optarg))
661 usage2 (_("Timeout interval must be a positive integer"), optarg);
662 else
663 timeout_interval = atoi (optarg);
664 break;
666 /* Test parameters */
667 case 'c': /* critical threshold */
668 critical_thresholds = optarg;
669 break;
670 case 'w': /* warning threshold */
671 warning_thresholds = optarg;
672 break;
673 case 'e': /* PRELIMINARY - may change */
674 case 'E': /* PRELIMINARY - may change */
675 if (!is_integer (optarg))
676 usage2 (_("Retries interval must be a positive integer"), optarg);
677 else
678 retries = atoi(optarg);
679 break;
680 case 'o': /* object identifier */
681 if ( strspn( optarg, "0123456789.," ) != strlen( optarg ) ) {
682 /*
683 * we have something other than digits, periods and comas,
684 * so we have a mib variable, rather than just an SNMP OID,
685 * so we have to actually read the mib files
686 */
687 needmibs = TRUE;
688 }
689 if (!oids) oids = calloc(MAX_OIDS, sizeof (char *));
690 for (ptr = strtok(optarg, ", "); ptr != NULL && j < MAX_OIDS; ptr = strtok(NULL, ", "), j++) {
691 oids[j] = strdup(ptr);
692 }
693 numoids = j;
694 if (c == 'E' || c == 'e') {
695 jj++;
696 ii++;
697 }
698 if (c == 'E')
699 eval_method[j+1] |= WARN_PRESENT;
700 else if (c == 'e')
701 eval_method[j+1] |= CRIT_PRESENT;
702 break;
703 case 's': /* string or substring */
704 strncpy (string_value, optarg, sizeof (string_value) - 1);
705 string_value[sizeof (string_value) - 1] = 0;
706 eval_method[jj++] = CRIT_STRING;
707 ii++;
708 break;
709 case 'R': /* regex */
710 cflags = REG_ICASE;
711 case 'r': /* regex */
712 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
713 strncpy (regex_expect, optarg, sizeof (regex_expect) - 1);
714 regex_expect[sizeof (regex_expect) - 1] = 0;
715 errcode = regcomp (&preg, regex_expect, cflags);
716 if (errcode != 0) {
717 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
718 printf (_("Could Not Compile Regular Expression"));
719 return ERROR;
720 }
721 eval_method[jj++] = CRIT_REGEX;
722 ii++;
723 break;
725 /* Format */
726 case 'd': /* delimiter */
727 delimiter = strscpy (delimiter, optarg);
728 break;
729 case 'D': /* output-delimiter */
730 output_delim = strscpy (output_delim, optarg);
731 break;
732 case 'l': /* label */
733 nlabels++;
734 if (nlabels >= labels_size) {
735 labels_size += 8;
736 labels = realloc (labels, labels_size);
737 if (labels == NULL)
738 die (STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels);
739 }
740 labels[nlabels - 1] = optarg;
741 ptr = thisarg (optarg);
742 labels[nlabels - 1] = ptr;
743 if (strstr (ptr, "'") == ptr)
744 labels[nlabels - 1] = ptr + 1;
745 while (ptr && (ptr = nextarg (ptr))) {
746 if (nlabels >= labels_size) {
747 labels_size += 8;
748 labels = realloc (labels, labels_size);
749 if (labels == NULL)
750 die (STATE_UNKNOWN, _("Could not reallocate labels\n"));
751 }
752 labels++;
753 ptr = thisarg (ptr);
754 if (strstr (ptr, "'") == ptr)
755 labels[nlabels - 1] = ptr + 1;
756 else
757 labels[nlabels - 1] = ptr;
758 }
759 break;
760 case 'u': /* units */
761 units = optarg;
762 nunits++;
763 if (nunits >= unitv_size) {
764 unitv_size += 8;
765 unitv = realloc (unitv, unitv_size);
766 if (unitv == NULL)
767 die (STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits);
768 }
769 unitv[nunits - 1] = optarg;
770 ptr = thisarg (optarg);
771 unitv[nunits - 1] = ptr;
772 if (strstr (ptr, "'") == ptr)
773 unitv[nunits - 1] = ptr + 1;
774 while (ptr && (ptr = nextarg (ptr))) {
775 if (nunits >= unitv_size) {
776 unitv_size += 8;
777 unitv = realloc (unitv, unitv_size);
778 if (units == NULL)
779 die (STATE_UNKNOWN, _("Could not realloc() units\n"));
780 }
781 nunits++;
782 ptr = thisarg (ptr);
783 if (strstr (ptr, "'") == ptr)
784 unitv[nunits - 1] = ptr + 1;
785 else
786 unitv[nunits - 1] = ptr;
787 }
788 break;
789 case L_CALCULATE_RATE:
790 if(calculate_rate==0)
791 np_enable_state(NULL, 1);
792 calculate_rate = 1;
793 break;
794 case L_RATE_MULTIPLIER:
795 if(!is_integer(optarg)||((rate_multiplier=atoi(optarg))<=0))
796 usage2(_("Rate multiplier must be a positive integer"),optarg);
797 break;
798 case L_INVERT_SEARCH:
799 invert_search=1;
800 break;
801 }
802 }
804 if (server_address == NULL)
805 server_address = argv[optind];
807 if (community == NULL)
808 community = strdup (DEFAULT_COMMUNITY);
810 return validate_arguments ();
811 }
814 /******************************************************************************
816 @@-
817 <sect3>
818 <title>validate_arguments</title>
820 <para>&PROTO_validate_arguments;</para>
822 <para>Checks to see if the default miblist needs to be loaded. Also verifies
823 the authentication and authorization combinations based on protocol version
824 selected.</para>
826 <para></para>
828 </sect3>
829 -@@
830 ******************************************************************************/
834 int
835 validate_arguments ()
836 {
837 /* check whether to load locally installed MIBS (CPU/disk intensive) */
838 if (miblist == NULL) {
839 if ( needmibs == TRUE ) {
840 miblist = strdup (DEFAULT_MIBLIST);
841 }else{
842 miblist = ""; /* don't read any mib files for numeric oids */
843 }
844 }
846 /* Check server_address is given */
847 if (server_address == NULL)
848 die(STATE_UNKNOWN, _("No host specified\n"));
850 /* Check oid is given */
851 if (numoids == 0)
852 die(STATE_UNKNOWN, _("No OIDs specified\n"));
854 if (proto == NULL)
855 asprintf(&proto, DEFAULT_PROTOCOL);
857 if ((strcmp(proto,"1") == 0) || (strcmp(proto, "2c")==0)) { /* snmpv1 or snmpv2c */
858 numauthpriv = 2;
859 authpriv = calloc (numauthpriv, sizeof (char *));
860 authpriv[0] = strdup ("-c");
861 authpriv[1] = strdup (community);
862 }
863 else if ( strcmp (proto, "3") == 0 ) { /* snmpv3 args */
864 if (seclevel == NULL)
865 asprintf(&seclevel, "noAuthNoPriv");
867 if (strcmp(seclevel, "noAuthNoPriv") == 0) {
868 numauthpriv = 2;
869 authpriv = calloc (numauthpriv, sizeof (char *));
870 authpriv[0] = strdup ("-l");
871 authpriv[1] = strdup ("noAuthNoPriv");
872 } else {
873 if (! ( (strcmp(seclevel, "authNoPriv")==0) || (strcmp(seclevel, "authPriv")==0) ) ) {
874 usage2 (_("Invalid seclevel"), seclevel);
875 }
877 if (authproto == NULL )
878 asprintf(&authproto, DEFAULT_AUTH_PROTOCOL);
880 if (secname == NULL)
881 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname");
883 if (authpasswd == NULL)
884 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd");
886 if ( strcmp(seclevel, "authNoPriv") == 0 ) {
887 numauthpriv = 8;
888 authpriv = calloc (numauthpriv, sizeof (char *));
889 authpriv[0] = strdup ("-l");
890 authpriv[1] = strdup ("authNoPriv");
891 authpriv[2] = strdup ("-a");
892 authpriv[3] = strdup (authproto);
893 authpriv[4] = strdup ("-u");
894 authpriv[5] = strdup (secname);
895 authpriv[6] = strdup ("-A");
896 authpriv[7] = strdup (authpasswd);
897 } else if ( strcmp(seclevel, "authPriv") == 0 ) {
898 if (privproto == NULL )
899 asprintf(&privproto, DEFAULT_PRIV_PROTOCOL);
901 if (privpasswd == NULL)
902 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd");
904 numauthpriv = 12;
905 authpriv = calloc (numauthpriv, sizeof (char *));
906 authpriv[0] = strdup ("-l");
907 authpriv[1] = strdup ("authPriv");
908 authpriv[2] = strdup ("-a");
909 authpriv[3] = strdup (authproto);
910 authpriv[4] = strdup ("-u");
911 authpriv[5] = strdup (secname);
912 authpriv[6] = strdup ("-A");
913 authpriv[7] = strdup (authpasswd);
914 authpriv[8] = strdup ("-x");
915 authpriv[9] = strdup (privproto);
916 authpriv[10] = strdup ("-X");
917 authpriv[11] = strdup (privpasswd);
918 }
919 }
921 }
922 else {
923 usage2 (_("Invalid SNMP version"), proto);
924 }
926 return OK;
927 }
931 /* trim leading whitespace
932 if there is a leading quote, make sure it balances */
934 char *
935 thisarg (char *str)
936 {
937 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */
938 if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */
939 if (strlen (str) == 1 || !strstr (str + 1, "'"))
940 die (STATE_UNKNOWN, _("Unbalanced quotes\n"));
941 }
942 return str;
943 }
947 /* if there's a leading quote, advance to the trailing quote
948 set the trailing quote to '\x0'
949 if the string continues, advance beyond the comma */
951 char *
952 nextarg (char *str)
953 {
954 if (strstr (str, "'") == str) {
955 str[0] = 0;
956 if (strlen (str) > 1) {
957 str = strstr (str + 1, "'");
958 return (++str);
959 }
960 else {
961 return NULL;
962 }
963 }
964 if (strstr (str, ",") == str) {
965 str[0] = 0;
966 if (strlen (str) > 1) {
967 return (++str);
968 }
969 else {
970 return NULL;
971 }
972 }
973 if ((str = strstr (str, ",")) && strlen (str) > 1) {
974 str[0] = 0;
975 return (++str);
976 }
977 return NULL;
978 }
982 void
983 print_help (void)
984 {
985 print_revision (progname, NP_VERSION);
987 printf (COPYRIGHT, copyright, email);
989 printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
991 printf ("\n\n");
993 print_usage ();
995 printf (UT_HELP_VRSN);
996 printf (UT_EXTRA_OPTS);
998 printf (UT_HOST_PORT, 'p', DEFAULT_PORT);
1000 /* SNMP and Authentication Protocol */
1001 printf (" %s\n", "-n, --next");
1002 printf (" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
1003 printf (" %s\n", "-P, --protocol=[1|2c|3]");
1004 printf (" %s\n", _("SNMP protocol version"));
1005 printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
1006 printf (" %s\n", _("SNMPv3 securityLevel"));
1007 printf (" %s\n", "-a, --authproto=[MD5|SHA]");
1008 printf (" %s\n", _("SNMPv3 auth proto"));
1009 printf (" %s\n", "-x, --privproto=[DES|AES]");
1010 printf (" %s\n", _("SNMPv3 priv proto (default DES)"));
1012 /* Authentication Tokens*/
1013 printf (" %s\n", "-C, --community=STRING");
1014 printf (" %s ", _("Optional community string for SNMP communication"));
1015 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY);
1016 printf (" %s\n", "-U, --secname=USERNAME");
1017 printf (" %s\n", _("SNMPv3 username"));
1018 printf (" %s\n", "-A, --authpassword=PASSWORD");
1019 printf (" %s\n", _("SNMPv3 authentication password"));
1020 printf (" %s\n", "-X, --privpasswd=PASSWORD");
1021 printf (" %s\n", _("SNMPv3 privacy password"));
1023 /* OID Stuff */
1024 printf (" %s\n", "-o, --oid=OID(s)");
1025 printf (" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
1026 printf (" %s\n", "-m, --miblist=STRING");
1027 printf (" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
1028 printf (" %s\n", _("for symbolic OIDs.)"));
1029 printf (" %s\n", "-d, --delimiter=STRING");
1030 printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER);
1031 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1032 printf (" %s\n", _("to be the data that should be used in the evaluation."));
1034 /* Tests Against Integers */
1035 printf (" %s\n", "-w, --warning=THRESHOLD(s)");
1036 printf (" %s\n", _("Warning threshold range(s)"));
1037 printf (" %s\n", "-c, --critical=THRESHOLD(s)");
1038 printf (" %s\n", _("Critical threshold range(s)"));
1039 printf (" %s\n", "--rate");
1040 printf (" %s\n", _("Enable rate calculation. See 'Rate Calculation' below"));
1041 printf (" %s\n", "--rate-multiplier");
1042 printf (" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
1044 /* Tests Against Strings */
1045 printf (" %s\n", "-s, --string=STRING");
1046 printf (" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
1047 printf (" %s\n", "-r, --ereg=REGEX");
1048 printf (" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
1049 printf (" %s\n", "-R, --eregi=REGEX");
1050 printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
1051 printf (" %s\n", "--invert-search");
1052 printf (" %s\n", _("Invert search result (CRITICAL if found)"));
1054 /* Output Formatting */
1055 printf (" %s\n", "-l, --label=STRING");
1056 printf (" %s\n", _("Prefix label for output from plugin"));
1057 printf (" %s\n", "-u, --units=STRING");
1058 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1059 printf (" %s\n", "-D, --output-delimiter=STRING");
1060 printf (" %s\n", _("Separates output on multiple OID requests"));
1062 printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1063 printf (" %s\n", "-e, --retries=INTEGER");
1064 printf (" %s\n", _("Number of retries to be used in the requests"));
1066 printf (UT_VERBOSE);
1068 printf ("\n");
1069 printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
1070 printf ("%s\n", _("if you don't have the package installed, you will need to download it from"));
1071 printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1073 printf ("\n");
1074 printf ("%s\n", _("Notes:"));
1075 printf (" %s\n", _("- Multiple OIDs may be indicated by a comma or space-delimited list (lists with"));
1076 printf (" %s %i %s\n", _("internal spaces must be quoted). Maximum:"), MAX_OIDS, _("OIDs."));
1078 printf(" -%s", UT_THRESHOLDS_NOTES);
1080 printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1081 printf (" %s\n", _("- Note that only one string and one regex may be checked at present"));
1082 printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1083 printf (" %s\n", _("returned from the SNMP query is an unsigned integer."));
1085 printf("\n");
1086 printf("%s\n", _("Rate Calculation:"));
1087 printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when"));
1088 printf(" %s\n", _("calculating the counter difference since the last check. check_snmp"));
1089 printf(" %s\n", _("saves the last state information in a file so that the rate per second"));
1090 printf(" %s\n", _("can be calculated. Use the --rate option to save state information."));
1091 printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK."));
1092 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
1093 printf(" %s\n", _("changing the arguments will create a new state file."));
1095 printf (UT_SUPPORT);
1096 }
1100 void
1101 print_usage (void)
1102 {
1103 printf ("%s\n", _("Usage:"));
1104 printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname);
1105 printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1106 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1107 printf ("[-m miblist] [-P snmp version] [-L seclevel] [-U secname] [-a authproto]\n");
1108 printf ("[-A authpasswd] [-x privproto] [-X privpasswd]\n");
1109 }