1 /*****************************************************************************
3 * Nagios check_snmp plugin
6 * Copyright (c) 1999-2007 Nagios Plugins Development Team
10 * This file contains the check_snmp plugin
12 * Check status of remote machines and obtain system information via SNMP
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.
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.
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/>.
29 *****************************************************************************/
31 const char *progname
= "check_snmp";
32 const char *copyright
= "1999-2007";
33 const char *email
= "nagiosplug-devel@lists.sourceforge.net";
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?"*":"")
53 #define CRIT_PRESENT 1
56 #define WARN_PRESENT 8
57 #define WARN_STRING 16
60 #define OID_COUNT_STEP 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
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)
72 #define COUNT_SEQ(c, bk, dq) switch(c[0]) {\
79 else if(!bk) { dq--; } \
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);
94 char regex_expect
[MAX_INPUT_BUFFER
] = "";
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
;
103 char *server_address
= NULL
;
104 char *community
= NULL
;
105 char **authpriv
= 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
;
114 size_t oids_size
= NULL
;
119 char string_value
[MAX_INPUT_BUFFER
] = "";
121 char **labels
= NULL
;
124 size_t labels_size
= OID_COUNT_STEP
;
126 size_t unitv_size
= OID_COUNT_STEP
;
130 int usesnmpgetnext
= FALSE
;
131 char *warning_thresholds
= NULL
;
132 char *critical_thresholds
= NULL
;
134 size_t thlds_size
= OID_COUNT_STEP
;
135 double *response_value
;
136 size_t response_size
= OID_COUNT_STEP
;
139 size_t eval_size
= OID_COUNT_STEP
;
142 char *miblist
= NULL
;
143 int needmibs
= FALSE
;
144 int calculate_rate
= 0;
145 int rate_multiplier
= 1;
146 state_data
*previous_state
;
147 double *previous_value
;
148 size_t previous_size
= OID_COUNT_STEP
;
152 static char *fix_snmp_range(char *th
)
156 if (!(colon
= strchr(th
, ':')))
160 left
= strtod(th
, NULL
);
161 right
= strtod(colon
+ 1, NULL
);
165 ret
= malloc(strlen(th
) + strlen(colon
+ 1) + 2);
166 sprintf(ret
, "@%s:%s", colon
+ 1, th
);
172 main (int argc
, char **argv
)
174 int i
, len
, line
, total_oids
;
175 unsigned int bk_count
= 0, dq_count
= 0;
176 int iresult
= STATE_UNKNOWN
;
177 int result
= STATE_UNKNOWN
;
179 int external_error
= 0;
180 char **command_line
= NULL
;
181 char *cl_hidden_auth
= NULL
;
182 char *oidname
= NULL
;
183 char *response
= NULL
;
184 char *mult_resp
= NULL
;
191 output chld_out
, chld_err
;
192 char *previous_string
=NULL
;
194 char *state_string
=NULL
;
195 size_t response_length
, current_length
, string_length
;
196 char *temp_string
=NULL
;
197 char *quote_string
=NULL
;
201 char *conv
= "12345678";
204 setlocale (LC_ALL
, "");
205 bindtextdomain (PACKAGE
, LOCALEDIR
);
206 textdomain (PACKAGE
);
208 labels
= malloc (labels_size
* sizeof(*labels
));
209 unitv
= malloc (unitv_size
* sizeof(*unitv
));
210 thlds
= malloc (thlds_size
* sizeof(*thlds
));
211 response_value
= malloc (response_size
* sizeof(*response_value
));
212 previous_value
= malloc (previous_size
* sizeof(*previous_value
));
213 eval_method
= calloc (eval_size
, sizeof(*eval_method
));
214 oids
= calloc(oids_size
, sizeof (char *));
216 label
= strdup ("SNMP");
218 port
= strdup (DEFAULT_PORT
);
219 outbuff
= strdup ("");
220 delimiter
= strdup (" = ");
221 output_delim
= strdup (DEFAULT_OUTPUT_DELIMITER
);
222 timeout_interval
= DEFAULT_TIMEOUT
;
223 retries
= DEFAULT_RETRIES
;
225 np_init( (char *) progname
, argc
, argv
);
227 /* Parse extra opts if any */
228 argv
=np_extra_opts (&argc
, argv
, progname
);
230 np_set_args(argc
, argv
);
234 if (process_arguments (argc
, argv
) == ERROR
)
235 usage4 (_("Could not parse arguments"));
238 if (!strcmp(label
, "SNMP"))
239 label
= strdup("SNMP RATE");
241 previous_state
= np_state_read();
242 if(previous_state
!=NULL
) {
243 /* Split colon separated values */
244 previous_string
= strdup((char *) previous_state
->data
);
245 while((ap
= strsep(&previous_string
, ":")) != NULL
) {
247 printf("State for %d=%s\n", i
, ap
);
248 while (i
>= previous_size
) {
249 previous_size
+= OID_COUNT_STEP
;
250 previous_value
= realloc(previous_value
, previous_size
* sizeof(*previous_value
));
252 previous_value
[i
++]=strtod(ap
,NULL
);
257 /* Populate the thresholds */
258 th_warn
=warning_thresholds
;
259 th_crit
=critical_thresholds
;
260 for (i
=0; i
<numoids
; i
++) {
261 char *w
= th_warn
? strndup(th_warn
, strcspn(th_warn
, ",")) : NULL
;
262 char *c
= th_crit
? strndup(th_crit
, strcspn(th_crit
, ",")) : NULL
;
263 /* translate "2:1" to "@1:2" for backwards compatibility */
264 w
= w
? fix_snmp_range(w
) : NULL
;
265 c
= c
? fix_snmp_range(c
) : NULL
;
267 while (i
>= thlds_size
) {
268 thlds_size
+= OID_COUNT_STEP
;
269 thlds
= realloc(thlds
, thlds_size
* sizeof(*thlds
));
272 /* Skip empty thresholds, while avoiding segfault */
273 set_thresholds(&thlds
[i
],
274 w
? strpbrk(w
, NP_THRESHOLDS_CHARS
) : NULL
,
275 c
? strpbrk(c
, NP_THRESHOLDS_CHARS
) : NULL
);
277 th_warn
=strchr(th_warn
, ',');
278 if (th_warn
) th_warn
++;
282 th_crit
=strchr(th_crit
, ',');
283 if (th_crit
) th_crit
++;
288 /* Create the command array to execute */
289 if(usesnmpgetnext
== TRUE
) {
290 snmpcmd
= strdup (PATH_TO_SNMPGETNEXT
);
292 snmpcmd
= strdup (PATH_TO_SNMPGET
);
295 /* 9 arguments to pass before authpriv options + 1 for host and numoids. Add one for terminating NULL */
296 command_line
= calloc (9 + numauthpriv
+ 1 + numoids
+ 1, sizeof (char *));
297 command_line
[0] = snmpcmd
;
298 command_line
[1] = strdup ("-t");
299 xasprintf (&command_line
[2], "%d", timeout_interval
);
300 command_line
[3] = strdup ("-r");
301 xasprintf (&command_line
[4], "%d", retries
);
302 command_line
[5] = strdup ("-m");
303 command_line
[6] = strdup (miblist
);
304 command_line
[7] = "-v";
305 command_line
[8] = strdup (proto
);
307 for (i
= 0; i
< numauthpriv
; i
++) {
308 command_line
[9 + i
] = authpriv
[i
];
311 xasprintf (&command_line
[9 + numauthpriv
], "%s:%s", server_address
, port
);
313 /* This is just for display purposes, so it can remain a string */
314 xasprintf(&cl_hidden_auth
, "%s -t %d -r %d -m %s -v %s %s %s:%s",
315 snmpcmd
, timeout_interval
, retries
, strlen(miblist
) ? miblist
: "''", proto
, "[authpriv]",
316 server_address
, port
);
318 for (i
= 0; i
< numoids
; i
++) {
319 command_line
[9 + numauthpriv
+ 1 + i
] = oids
[i
];
320 xasprintf(&cl_hidden_auth
, "%s %s", cl_hidden_auth
, oids
[i
]);
323 command_line
[9 + numauthpriv
+ 1 + numoids
] = NULL
;
326 printf ("%s\n", cl_hidden_auth
);
328 /* Run the command */
329 return_code
= cmd_run_array (command_line
, &chld_out
, &chld_err
, 0);
331 /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs,
332 only return state unknown if return code is non zero or there is no stdout.
333 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
335 if (return_code
!= 0)
337 if (chld_out
.lines
== 0)
339 if (external_error
) {
340 if (chld_err
.lines
> 0) {
341 printf (_("External command error: %s\n"), chld_err
.line
[0]);
342 for (i
= 1; i
< chld_err
.lines
; i
++) {
343 printf ("%s\n", chld_err
.line
[i
]);
346 printf(_("External command error with no output (return code: %d)\n"), return_code
);
348 exit (STATE_UNKNOWN
);
352 for (i
= 0; i
< chld_out
.lines
; i
++) {
353 printf ("%s\n", chld_out
.line
[i
]);
357 for (line
=0, i
=0; line
< chld_out
.lines
; line
++, i
++) {
363 ptr
= chld_out
.line
[line
];
364 oidname
= strpcpy (oidname
, ptr
, delimiter
);
365 response
= strstr (ptr
, delimiter
);
366 if (response
== NULL
)
370 printf("Processing oid %i (line %i)\n oidname: %s\n response: %s\n", i
+1, line
+1, oidname
, response
);
373 /* Clean up type array - Sol10 does not necessarily zero it out */
374 bzero(type
, sizeof(type
));
377 /* We strip out the datatype indicator for PHBs */
378 if (strstr (response
, "Gauge: ")) {
379 show
= strstr (response
, "Gauge: ") + 7;
381 else if (strstr (response
, "Gauge32: ")) {
382 show
= strstr (response
, "Gauge32: ") + 9;
384 else if (strstr (response
, "Counter32: ")) {
385 show
= strstr (response
, "Counter32: ") + 11;
390 else if (strstr (response
, "Counter64: ")) {
391 show
= strstr (response
, "Counter64: ") + 11;
396 else if (strstr (response
, "INTEGER: ")) {
397 show
= strstr (response
, "INTEGER: ") + 9;
399 else if (strstr (response
, "STRING: ")) {
400 show
= strstr (response
, "STRING: ") + 8;
403 /* Get the rest of the string on multi-line strings */
405 COUNT_SEQ(ptr
, bk_count
, dq_count
)
406 while (dq_count
&& ptr
[0] != '\n' && ptr
[0] != '\0') {
408 GOBBLE_TOS(ptr
, "\n\"\\")
409 COUNT_SEQ(ptr
, bk_count
, dq_count
)
412 if (dq_count
) { /* unfinished line */
413 /* copy show verbatim first */
414 if (!mult_resp
) mult_resp
= strdup("");
415 xasprintf (&mult_resp
, "%s%s:\n%s\n", mult_resp
, oids
[i
], show
);
416 /* then strip out unmatched double-quote from single-line output */
417 if (show
[0] == '"') show
++;
419 /* Keep reading until we match end of double-quoted string */
420 for (line
++; line
< chld_out
.lines
; line
++) {
421 ptr
= chld_out
.line
[line
];
422 xasprintf (&mult_resp
, "%s%s\n", mult_resp
, ptr
);
424 COUNT_SEQ(ptr
, bk_count
, dq_count
)
425 while (dq_count
&& ptr
[0] != '\n' && ptr
[0] != '\0') {
427 GOBBLE_TOS(ptr
, "\n\"\\")
428 COUNT_SEQ(ptr
, bk_count
, dq_count
)
430 /* Break for loop before next line increment when done */
431 if (!dq_count
) break;
436 else if (strstr (response
, "Timeticks: ")) {
437 show
= strstr (response
, "Timeticks: ");
442 iresult
= STATE_DEPENDENT
;
444 /* Process this block for numeric comparisons */
445 /* Make some special values,like Timeticks numeric only if a threshold is defined */
446 if (thlds
[i
]->warning
|| thlds
[i
]->critical
|| calculate_rate
) {
447 ptr
= strpbrk (show
, "0123456789");
449 die (STATE_UNKNOWN
,_("No valid data returned (%s)\n"), show
);
450 while (i
>= response_size
) {
451 response_size
+= OID_COUNT_STEP
;
452 response_value
= realloc(response_value
, response_size
* sizeof(*response_value
));
454 response_value
[i
] = strtod (ptr
, NULL
);
457 if (previous_state
!=NULL
) {
458 duration
= current_time
-previous_state
->time
;
460 die(STATE_UNKNOWN
,_("Time duration between plugin calls is invalid"));
461 temp_double
= response_value
[i
]-previous_value
[i
];
462 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
464 if(temp_double
<(double)0.0)
465 temp_double
+=(double)4294967296.0; /* 2^32 */
466 if(temp_double
<(double)0.0)
467 temp_double
+=(double)18446744069414584320.0; /* 2^64-2^32 */;
469 /* Convert to per second, then use multiplier */
470 temp_double
= temp_double
/duration
*rate_multiplier
;
471 iresult
= get_status(temp_double
, thlds
[i
]);
472 xasprintf (&show
, conv
, temp_double
);
475 iresult
= get_status(response_value
[i
], thlds
[i
]);
476 xasprintf (&show
, conv
, response_value
[i
]);
480 /* Process this block for string matching */
481 else if (eval_size
> i
&& eval_method
[i
] & CRIT_STRING
) {
482 if (strcmp (show
, string_value
))
483 iresult
= (invert_search
==0) ? STATE_CRITICAL
: STATE_OK
;
485 iresult
= (invert_search
==0) ? STATE_OK
: STATE_CRITICAL
;
488 /* Process this block for regex matching */
489 else if (eval_size
> i
&& eval_method
[i
] & CRIT_REGEX
) {
490 excode
= regexec (&preg
, response
, 10, pmatch
, eflags
);
492 iresult
= (invert_search
==0) ? STATE_OK
: STATE_CRITICAL
;
494 else if (excode
!= REG_NOMATCH
) {
495 regerror (excode
, &preg
, errbuf
, MAX_INPUT_BUFFER
);
496 printf (_("Execute Error: %s\n"), errbuf
);
497 exit (STATE_CRITICAL
);
500 iresult
= (invert_search
==0) ? STATE_CRITICAL
: STATE_OK
;
504 /* Process this block for existence-nonexistence checks */
505 /* TV: Should this be outside of this else block? */
507 if (eval_size
> i
&& eval_method
[i
] & CRIT_PRESENT
)
508 iresult
= STATE_CRITICAL
;
509 else if (eval_size
> i
&& eval_method
[i
] & WARN_PRESENT
)
510 iresult
= STATE_WARNING
;
511 else if (response
&& iresult
== STATE_DEPENDENT
)
515 /* Result is the worst outcome of all the OIDs tested */
516 result
= max_state (result
, iresult
);
518 /* Prepend a label for this OID if there is one */
519 if (nlabels
>= (size_t)1 && (size_t)i
< nlabels
&& labels
[i
] != NULL
)
520 xasprintf (&outbuff
, "%s%s%s %s%s%s", outbuff
,
521 (i
== 0) ? " " : output_delim
,
522 labels
[i
], mark (iresult
), show
, mark (iresult
));
524 xasprintf (&outbuff
, "%s%s%s%s%s", outbuff
, (i
== 0) ? " " : output_delim
,
525 mark (iresult
), show
, mark (iresult
));
527 /* Append a unit string for this OID if there is one */
528 if (nunits
> (size_t)0 && (size_t)i
< nunits
&& unitv
[i
] != NULL
)
529 xasprintf (&outbuff
, "%s %s", outbuff
, unitv
[i
]);
531 /* Write perfdata with whatever can be parsed by strtod, if possible */
535 if (perf_labels
&& nlabels
>= (size_t)1 && (size_t)i
< nlabels
&& labels
[i
] != NULL
)
536 temp_string
=labels
[i
];
539 if (strpbrk (temp_string
, " ='\"") == NULL
) {
540 strncat(perfstr
, temp_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
542 if (strpbrk (temp_string
, "'") == NULL
) {
547 strncat(perfstr
, quote_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
548 strncat(perfstr
, temp_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
549 strncat(perfstr
, quote_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
551 strncat(perfstr
, "=", sizeof(perfstr
)-strlen(perfstr
)-1);
552 len
= sizeof(perfstr
)-strlen(perfstr
)-1;
553 strncat(perfstr
, show
, len
>ptr
-show
? ptr
-show
: len
);
556 strncat(perfstr
, type
, sizeof(perfstr
)-strlen(perfstr
)-1);
557 strncat(perfstr
, " ", sizeof(perfstr
)-strlen(perfstr
)-1);
562 /* Save state data, as all data collected now */
565 state_string
=malloc(string_length
);
566 if(state_string
==NULL
)
567 die(STATE_UNKNOWN
, _("Cannot malloc"));
570 for(i
=0; i
<total_oids
; i
++) {
571 xasprintf(&temp_string
,"%.0f",response_value
[i
]);
572 if(temp_string
==NULL
)
573 die(STATE_UNKNOWN
,_("Cannot asprintf()"));
574 response_length
= strlen(temp_string
);
575 if(current_length
+response_length
>string_length
) {
576 string_length
=current_length
+1024;
577 state_string
=realloc(state_string
,string_length
);
578 if(state_string
==NULL
)
579 die(STATE_UNKNOWN
, _("Cannot realloc()"));
581 strcpy(&state_string
[current_length
],temp_string
);
582 current_length
=current_length
+response_length
;
583 state_string
[current_length
]=':';
587 state_string
[--current_length
]='\0';
589 printf("State string=%s\n",state_string
);
591 /* This is not strictly the same as time now, but any subtle variations will cancel out */
592 np_state_write_string(current_time
, state_string
);
593 if(previous_state
==NULL
) {
594 /* Or should this be highest state? */
595 die( STATE_OK
, _("No previous data to calculate rate - assume okay" ) );
599 printf ("%s %s -%s %s\n", label
, state_text (result
), outbuff
, perfstr
);
600 if (mult_resp
) printf ("%s", mult_resp
);
607 /* process command-line arguments */
609 process_arguments (int argc
, char **argv
)
613 int j
= 0, jj
= 0, ii
= 0;
616 static struct option longopts
[] = {
618 {"community", required_argument
, 0, 'C'},
619 {"oid", required_argument
, 0, 'o'},
620 {"object", required_argument
, 0, 'o'},
621 {"delimiter", required_argument
, 0, 'd'},
622 {"output-delimiter", required_argument
, 0, 'D'},
623 {"string", required_argument
, 0, 's'},
624 {"timeout", required_argument
, 0, 't'},
625 {"regex", required_argument
, 0, 'r'},
626 {"ereg", required_argument
, 0, 'r'},
627 {"eregi", required_argument
, 0, 'R'},
628 {"label", required_argument
, 0, 'l'},
629 {"units", required_argument
, 0, 'u'},
630 {"port", required_argument
, 0, 'p'},
631 {"retries", required_argument
, 0, 'e'},
632 {"miblist", required_argument
, 0, 'm'},
633 {"protocol", required_argument
, 0, 'P'},
634 {"seclevel", required_argument
, 0, 'L'},
635 {"secname", required_argument
, 0, 'U'},
636 {"authproto", required_argument
, 0, 'a'},
637 {"privproto", required_argument
, 0, 'x'},
638 {"authpasswd", required_argument
, 0, 'A'},
639 {"privpasswd", required_argument
, 0, 'X'},
640 {"next", no_argument
, 0, 'n'},
641 {"rate", no_argument
, 0, L_CALCULATE_RATE
},
642 {"rate-multiplier", required_argument
, 0, L_RATE_MULTIPLIER
},
643 {"invert-search", no_argument
, 0, L_INVERT_SEARCH
},
644 {"perf-oids", no_argument
, 0, 'O'},
651 /* reverse compatibility for very old non-POSIX usage forms */
652 for (c
= 1; c
< argc
; c
++) {
653 if (strcmp ("-to", argv
[c
]) == 0)
654 strcpy (argv
[c
], "-t");
655 if (strcmp ("-wv", argv
[c
]) == 0)
656 strcpy (argv
[c
], "-w");
657 if (strcmp ("-cv", argv
[c
]) == 0)
658 strcpy (argv
[c
], "-c");
662 c
= getopt_long (argc
, argv
, "nhvVOt:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:L:U:a:x:A:X:",
665 if (c
== -1 || c
== EOF
)
669 case '?': /* usage */
674 case 'V': /* version */
675 print_revision (progname
, NP_VERSION
);
677 case 'v': /* verbose */
681 /* Connection info */
682 case 'C': /* group or community */
685 case 'H': /* Host or server */
686 server_address
= optarg
;
688 case 'p': /* TCP port number */
691 case 'm': /* List of MIBS */
694 case 'n': /* usesnmpgetnext */
695 usesnmpgetnext
= TRUE
;
697 case 'P': /* SNMP protocol version */
700 case 'L': /* security level */
703 case 'U': /* security username */
706 case 'a': /* auth protocol */
709 case 'x': /* priv protocol */
712 case 'A': /* auth passwd */
715 case 'X': /* priv passwd */
718 case 't': /* timeout period */
719 if (!is_integer (optarg
))
720 usage2 (_("Timeout interval must be a positive integer"), optarg
);
722 timeout_interval
= atoi (optarg
);
725 /* Test parameters */
726 case 'c': /* critical threshold */
727 critical_thresholds
= optarg
;
729 case 'w': /* warning threshold */
730 warning_thresholds
= optarg
;
732 case 'e': /* PRELIMINARY - may change */
733 case 'E': /* PRELIMINARY - may change */
734 if (!is_integer (optarg
))
735 usage2 (_("Retries interval must be a positive integer"), optarg
);
737 retries
= atoi(optarg
);
739 case 'o': /* object identifier */
740 if ( strspn( optarg
, "0123456789.," ) != strlen( optarg
) ) {
742 * we have something other than digits, periods and comas,
743 * so we have a mib variable, rather than just an SNMP OID,
744 * so we have to actually read the mib files
748 for (ptr
= strtok(optarg
, ", "); ptr
!= NULL
; ptr
= strtok(NULL
, ", "), j
++) {
749 while (j
>= oids_size
) {
750 oids_size
+= OID_COUNT_STEP
;
751 oids
= realloc(oids
, oids_size
* sizeof (*oids
));
753 oids
[j
] = strdup(ptr
);
756 if (c
== 'E' || c
== 'e') {
759 while (j
+1 >= eval_size
) {
760 eval_size
+= OID_COUNT_STEP
;
761 eval_method
= realloc(eval_method
, eval_size
* sizeof(*eval_method
));
762 memset(eval_method
+ eval_size
- OID_COUNT_STEP
, 0, 8);
765 eval_method
[j
+1] |= WARN_PRESENT
;
767 eval_method
[j
+1] |= CRIT_PRESENT
;
770 case 's': /* string or substring */
771 strncpy (string_value
, optarg
, sizeof (string_value
) - 1);
772 string_value
[sizeof (string_value
) - 1] = 0;
773 while (jj
>= eval_size
) {
774 eval_size
+= OID_COUNT_STEP
;
775 eval_method
= realloc(eval_method
, eval_size
* sizeof(*eval_method
));
776 memset(eval_method
+ eval_size
- OID_COUNT_STEP
, 0, 8);
778 eval_method
[jj
++] = CRIT_STRING
;
781 case 'R': /* regex */
783 case 'r': /* regex */
784 cflags
|= REG_EXTENDED
| REG_NOSUB
| REG_NEWLINE
;
785 strncpy (regex_expect
, optarg
, sizeof (regex_expect
) - 1);
786 regex_expect
[sizeof (regex_expect
) - 1] = 0;
787 errcode
= regcomp (&preg
, regex_expect
, cflags
);
789 regerror (errcode
, &preg
, errbuf
, MAX_INPUT_BUFFER
);
790 printf (_("Could Not Compile Regular Expression"));
793 while (jj
>= eval_size
) {
794 eval_size
+= OID_COUNT_STEP
;
795 eval_method
= realloc(eval_method
, eval_size
* sizeof(*eval_method
));
796 memset(eval_method
+ eval_size
- OID_COUNT_STEP
, 0, 8);
798 eval_method
[jj
++] = CRIT_REGEX
;
803 case 'd': /* delimiter */
804 delimiter
= strscpy (delimiter
, optarg
);
806 case 'D': /* output-delimiter */
807 output_delim
= strscpy (output_delim
, optarg
);
809 case 'l': /* label */
811 if (nlabels
> labels_size
) {
813 labels
= realloc (labels
, labels_size
* sizeof(*labels
));
815 die (STATE_UNKNOWN
, _("Could not reallocate labels[%d]"), (int)nlabels
);
817 labels
[nlabels
- 1] = optarg
;
818 ptr
= thisarg (optarg
);
819 labels
[nlabels
- 1] = ptr
;
821 labels
[nlabels
- 1] = ptr
+ 1;
822 while (ptr
&& (ptr
= nextarg (ptr
))) {
824 if (nlabels
> labels_size
) {
826 labels
= realloc (labels
, labels_size
* sizeof(*labels
));
828 die (STATE_UNKNOWN
, _("Could not reallocate labels\n"));
832 labels
[nlabels
- 1] = ptr
+ 1;
834 labels
[nlabels
- 1] = ptr
;
837 case 'u': /* units */
840 if (nunits
> unitv_size
) {
842 unitv
= realloc (unitv
, unitv_size
* sizeof(*unitv
));
844 die (STATE_UNKNOWN
, _("Could not reallocate units [%d]\n"), (int)nunits
);
846 unitv
[nunits
- 1] = optarg
;
847 ptr
= thisarg (optarg
);
848 unitv
[nunits
- 1] = ptr
;
850 unitv
[nunits
- 1] = ptr
+ 1;
851 while (ptr
&& (ptr
= nextarg (ptr
))) {
852 if (nunits
> unitv_size
) {
854 unitv
= realloc (unitv
, unitv_size
* sizeof(*unitv
));
856 die (STATE_UNKNOWN
, _("Could not realloc() units\n"));
861 unitv
[nunits
- 1] = ptr
+ 1;
863 unitv
[nunits
- 1] = ptr
;
866 case L_CALCULATE_RATE
:
867 if(calculate_rate
==0)
868 np_enable_state(NULL
, 1);
871 case L_RATE_MULTIPLIER
:
872 if(!is_integer(optarg
)||((rate_multiplier
=atoi(optarg
))<=0))
873 usage2(_("Rate multiplier must be a positive integer"),optarg
);
875 case L_INVERT_SEARCH
:
884 if (server_address
== NULL
)
885 server_address
= argv
[optind
];
887 if (community
== NULL
)
888 community
= strdup (DEFAULT_COMMUNITY
);
890 return validate_arguments ();
894 /******************************************************************************
898 <title>validate_arguments</title>
900 <para>&PROTO_validate_arguments;</para>
902 <para>Checks to see if the default miblist needs to be loaded. Also verifies
903 the authentication and authorization combinations based on protocol version
910 ******************************************************************************/
915 validate_arguments ()
917 /* check whether to load locally installed MIBS (CPU/disk intensive) */
918 if (miblist
== NULL
) {
919 if ( needmibs
== TRUE
) {
920 miblist
= strdup (DEFAULT_MIBLIST
);
922 miblist
= ""; /* don't read any mib files for numeric oids */
926 /* Check server_address is given */
927 if (server_address
== NULL
)
928 die(STATE_UNKNOWN
, _("No host specified\n"));
930 /* Check oid is given */
932 die(STATE_UNKNOWN
, _("No OIDs specified\n"));
935 xasprintf(&proto
, DEFAULT_PROTOCOL
);
937 if ((strcmp(proto
,"1") == 0) || (strcmp(proto
, "2c")==0)) { /* snmpv1 or snmpv2c */
939 authpriv
= calloc (numauthpriv
, sizeof (char *));
940 authpriv
[0] = strdup ("-c");
941 authpriv
[1] = strdup (community
);
943 else if ( strcmp (proto
, "3") == 0 ) { /* snmpv3 args */
944 if (seclevel
== NULL
)
945 xasprintf(&seclevel
, "noAuthNoPriv");
947 if (strcmp(seclevel
, "noAuthNoPriv") == 0) {
949 authpriv
= calloc (numauthpriv
, sizeof (char *));
950 authpriv
[0] = strdup ("-l");
951 authpriv
[1] = strdup ("noAuthNoPriv");
953 if (! ( (strcmp(seclevel
, "authNoPriv")==0) || (strcmp(seclevel
, "authPriv")==0) ) ) {
954 usage2 (_("Invalid seclevel"), seclevel
);
957 if (authproto
== NULL
)
958 xasprintf(&authproto
, DEFAULT_AUTH_PROTOCOL
);
961 die(STATE_UNKNOWN
, _("Required parameter: %s\n"), "secname");
963 if (authpasswd
== NULL
)
964 die(STATE_UNKNOWN
, _("Required parameter: %s\n"), "authpasswd");
966 if ( strcmp(seclevel
, "authNoPriv") == 0 ) {
968 authpriv
= calloc (numauthpriv
, sizeof (char *));
969 authpriv
[0] = strdup ("-l");
970 authpriv
[1] = strdup ("authNoPriv");
971 authpriv
[2] = strdup ("-a");
972 authpriv
[3] = strdup (authproto
);
973 authpriv
[4] = strdup ("-u");
974 authpriv
[5] = strdup (secname
);
975 authpriv
[6] = strdup ("-A");
976 authpriv
[7] = strdup (authpasswd
);
977 } else if ( strcmp(seclevel
, "authPriv") == 0 ) {
978 if (privproto
== NULL
)
979 xasprintf(&privproto
, DEFAULT_PRIV_PROTOCOL
);
981 if (privpasswd
== NULL
)
982 die(STATE_UNKNOWN
, _("Required parameter: %s\n"), "privpasswd");
985 authpriv
= calloc (numauthpriv
, sizeof (char *));
986 authpriv
[0] = strdup ("-l");
987 authpriv
[1] = strdup ("authPriv");
988 authpriv
[2] = strdup ("-a");
989 authpriv
[3] = strdup (authproto
);
990 authpriv
[4] = strdup ("-u");
991 authpriv
[5] = strdup (secname
);
992 authpriv
[6] = strdup ("-A");
993 authpriv
[7] = strdup (authpasswd
);
994 authpriv
[8] = strdup ("-x");
995 authpriv
[9] = strdup (privproto
);
996 authpriv
[10] = strdup ("-X");
997 authpriv
[11] = strdup (privpasswd
);
1003 usage2 (_("Invalid SNMP version"), proto
);
1011 /* trim leading whitespace
1012 if there is a leading quote, make sure it balances */
1017 str
+= strspn (str
, " \t\r\n"); /* trim any leading whitespace */
1018 if (str
[0] == '\'') { /* handle SIMPLE quoted strings */
1019 if (strlen (str
) == 1 || !strstr (str
+ 1, "'"))
1020 die (STATE_UNKNOWN
, _("Unbalanced quotes\n"));
1027 /* if there's a leading quote, advance to the trailing quote
1028 set the trailing quote to '\x0'
1029 if the string continues, advance beyond the comma */
1034 if (str
[0] == '\'') {
1036 if (strlen (str
) > 1) {
1037 str
= strstr (str
+ 1, "'");
1044 if (str
[0] == ',') {
1046 if (strlen (str
) > 1) {
1053 if ((str
= strstr (str
, ",")) && strlen (str
) > 1) {
1065 print_revision (progname
, NP_VERSION
);
1067 printf (COPYRIGHT
, copyright
, email
);
1069 printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
1075 printf (UT_HELP_VRSN
);
1076 printf (UT_EXTRA_OPTS
);
1078 printf (UT_HOST_PORT
, 'p', DEFAULT_PORT
);
1080 /* SNMP and Authentication Protocol */
1081 printf (" %s\n", "-n, --next");
1082 printf (" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
1083 printf (" %s\n", "-P, --protocol=[1|2c|3]");
1084 printf (" %s\n", _("SNMP protocol version"));
1085 printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
1086 printf (" %s\n", _("SNMPv3 securityLevel"));
1087 printf (" %s\n", "-a, --authproto=[MD5|SHA]");
1088 printf (" %s\n", _("SNMPv3 auth proto"));
1089 printf (" %s\n", "-x, --privproto=[DES|AES]");
1090 printf (" %s\n", _("SNMPv3 priv proto (default DES)"));
1092 /* Authentication Tokens*/
1093 printf (" %s\n", "-C, --community=STRING");
1094 printf (" %s ", _("Optional community string for SNMP communication"));
1095 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY
);
1096 printf (" %s\n", "-U, --secname=USERNAME");
1097 printf (" %s\n", _("SNMPv3 username"));
1098 printf (" %s\n", "-A, --authpassword=PASSWORD");
1099 printf (" %s\n", _("SNMPv3 authentication password"));
1100 printf (" %s\n", "-X, --privpasswd=PASSWORD");
1101 printf (" %s\n", _("SNMPv3 privacy password"));
1104 printf (" %s\n", "-o, --oid=OID(s)");
1105 printf (" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
1106 printf (" %s\n", "-m, --miblist=STRING");
1107 printf (" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
1108 printf (" %s\n", _("for symbolic OIDs.)"));
1109 printf (" %s\n", "-d, --delimiter=STRING");
1110 printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER
);
1111 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1112 printf (" %s\n", _("to be the data that should be used in the evaluation."));
1114 /* Tests Against Integers */
1115 printf (" %s\n", "-w, --warning=THRESHOLD(s)");
1116 printf (" %s\n", _("Warning threshold range(s)"));
1117 printf (" %s\n", "-c, --critical=THRESHOLD(s)");
1118 printf (" %s\n", _("Critical threshold range(s)"));
1119 printf (" %s\n", "--rate");
1120 printf (" %s\n", _("Enable rate calculation. See 'Rate Calculation' below"));
1121 printf (" %s\n", "--rate-multiplier");
1122 printf (" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
1124 /* Tests Against Strings */
1125 printf (" %s\n", "-s, --string=STRING");
1126 printf (" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
1127 printf (" %s\n", "-r, --ereg=REGEX");
1128 printf (" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
1129 printf (" %s\n", "-R, --eregi=REGEX");
1130 printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
1131 printf (" %s\n", "--invert-search");
1132 printf (" %s\n", _("Invert search result (CRITICAL if found)"));
1134 /* Output Formatting */
1135 printf (" %s\n", "-l, --label=STRING");
1136 printf (" %s\n", _("Prefix label for output from plugin"));
1137 printf (" %s\n", "-u, --units=STRING");
1138 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1139 printf (" %s\n", "-D, --output-delimiter=STRING");
1140 printf (" %s\n", _("Separates output on multiple OID requests"));
1142 printf (UT_TIMEOUT
, DEFAULT_SOCKET_TIMEOUT
);
1143 printf (" %s\n", "-e, --retries=INTEGER");
1144 printf (" %s\n", _("Number of retries to be used in the requests"));
1146 printf (" %s\n", "-O, --perf-oids");
1147 printf (" %s\n", _("Label performance data with OIDs instead of --label's"));
1149 printf (UT_VERBOSE
);
1152 printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
1153 printf ("%s\n", _("if you don't have the package installed, you will need to download it from"));
1154 printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1157 printf ("%s\n", _("Notes:"));
1158 printf (" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited "));
1159 printf (" %s %i %s\n", _("list (lists with internal spaces must be quoted)."));
1161 printf(" -%s", UT_THRESHOLDS_NOTES
);
1163 printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1164 printf (" %s\n", _("- Note that only one string and one regex may be checked at present"));
1165 printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1166 printf (" %s\n", _("returned from the SNMP query is an unsigned integer."));
1169 printf("%s\n", _("Rate Calculation:"));
1170 printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when"));
1171 printf(" %s\n", _("calculating the counter difference since the last check. check_snmp"));
1172 printf(" %s\n", _("saves the last state information in a file so that the rate per second"));
1173 printf(" %s\n", _("can be calculated. Use the --rate option to save state information."));
1174 printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK."));
1175 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
1176 printf(" %s\n", _("changing the arguments will create a new state file."));
1178 printf (UT_SUPPORT
);
1186 printf ("%s\n", _("Usage:"));
1187 printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname
);
1188 printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1189 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1190 printf ("[-m miblist] [-P snmp version] [-L seclevel] [-U secname] [-a authproto]\n");
1191 printf ("[-A authpasswd] [-x privproto] [-X privpasswd]\n");