1 /*****************************************************************************
3 * Monitoring check_snmp plugin
6 * Copyright (c) 1999-2007 Monitoring 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
= "devel@monitoring-plugins.org";
38 #include "utils_cmd.h"
40 #define DEFAULT_COMMUNITY "public"
41 #define DEFAULT_PORT "161"
42 #define DEFAULT_MIBLIST "ALL"
43 #define DEFAULT_PROTOCOL "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 " "
49 #define DEFAULT_BUFFER_SIZE 100
51 #define mark(a) ((a)!=0?"*":"")
54 #define CRIT_PRESENT 1
57 #define WARN_PRESENT 8
59 #define OID_COUNT_STEP 8
61 /* Longopts only arguments */
62 #define L_CALCULATE_RATE CHAR_MAX+1
63 #define L_RATE_MULTIPLIER CHAR_MAX+2
64 #define L_INVERT_SEARCH CHAR_MAX+3
65 #define L_OFFSET CHAR_MAX+4
66 #define L_IGNORE_MIB_PARSING_ERRORS CHAR_MAX+5
68 /* Gobble to string - stop incrementing c when c[0] match one of the
70 #define GOBBLE_TOS(c, s) while(c[0]!='\0' && strchr(s, c[0])==NULL) { c++; }
71 /* Given c, keep track of backslashes (bk) and double-quotes (dq)
73 #define COUNT_SEQ(c, bk, dq) switch(c[0]) {\
80 else if(!bk) { dq--; } \
87 static int process_arguments (int, char **);
88 static int validate_arguments (void);
89 static char *thisarg (char *str
);
90 static char *nextarg (char *str
);
91 void print_usage (void);
92 static void print_help (void);
93 static char *multiply (char *str
);
96 static char regex_expect
[MAX_INPUT_BUFFER
] = "";
98 static regmatch_t pmatch
[10];
99 static char errbuf
[MAX_INPUT_BUFFER
] = "";
100 static char perfstr
[MAX_INPUT_BUFFER
] = "| ";
101 static int cflags
= REG_EXTENDED
| REG_NOSUB
| REG_NEWLINE
;
102 static int eflags
= 0;
103 static int errcode
, excode
;
105 static char *server_address
= NULL
;
106 static char *community
= NULL
;
107 static char **contextargs
= NULL
;
108 static char *context
= NULL
;
109 static char **authpriv
= NULL
;
110 static char *proto
= NULL
;
111 static char *seclevel
= NULL
;
112 static char *secname
= NULL
;
113 static char *authproto
= NULL
;
114 static char *privproto
= NULL
;
115 static char *authpasswd
= NULL
;
116 static char *privpasswd
= NULL
;
117 static int nulloid
= STATE_UNKNOWN
;
118 static char **oids
= NULL
;
119 static size_t oids_size
= 0;
123 static char *snmpcmd
;
124 static char string_value
[MAX_INPUT_BUFFER
] = "";
125 static int invert_search
=0;
126 static char **labels
= NULL
;
127 static char **unitv
= NULL
;
128 static size_t nlabels
= 0;
129 static size_t labels_size
= OID_COUNT_STEP
;
130 static size_t nunits
= 0;
131 static size_t unitv_size
= OID_COUNT_STEP
;
132 static size_t numoids
= 0;
133 static int numauthpriv
= 0;
134 static int numcontext
= 0;
135 static int verbose
= 0;
136 static bool usesnmpgetnext
= false;
137 static char *warning_thresholds
= NULL
;
138 static char *critical_thresholds
= NULL
;
139 static thresholds
**thlds
;
140 static size_t thlds_size
= OID_COUNT_STEP
;
141 static double *response_value
;
142 static size_t response_size
= OID_COUNT_STEP
;
143 static int retries
= 0;
144 static int *eval_method
;
145 static size_t eval_size
= OID_COUNT_STEP
;
146 static char *delimiter
;
147 static char *output_delim
;
148 static char *miblist
= NULL
;
149 static bool needmibs
= false;
150 static int calculate_rate
= 0;
151 static double offset
= 0.0;
152 static int rate_multiplier
= 1;
153 static state_data
*previous_state
;
154 static double *previous_value
;
155 static size_t previous_size
= OID_COUNT_STEP
;
156 static int perf_labels
= 1;
157 static char* ip_version
= "";
158 static double multiplier
= 1.0;
159 static char *fmtstr
= "";
160 static bool fmtstr_set
= false;
161 static char buffer
[DEFAULT_BUFFER_SIZE
];
162 static bool ignore_mib_parsing_errors
= false;
164 static char *fix_snmp_range(char *th
)
169 if ((colon
= strchr(th
, ':')) == NULL
|| *(colon
+ 1) == '\0')
172 left
= strtod(th
, NULL
);
173 right
= strtod(colon
+ 1, NULL
);
177 if ((ret
= malloc(strlen(th
) + 2)) == NULL
)
178 die(STATE_UNKNOWN
, _("Cannot malloc"));
180 sprintf(ret
, "@%s:%s", colon
+ 1, th
);
186 main (int argc
, char **argv
)
190 unsigned int bk_count
= 0, dq_count
= 0;
191 int iresult
= STATE_UNKNOWN
;
192 int result
= STATE_UNKNOWN
;
194 int external_error
= 0;
195 char **command_line
= NULL
;
196 char *cl_hidden_auth
= NULL
;
197 char *oidname
= NULL
;
198 char *response
= NULL
;
199 char *mult_resp
= NULL
;
206 output chld_out
, chld_err
;
207 char *previous_string
=NULL
;
209 char *state_string
=NULL
;
210 size_t response_length
, current_length
, string_length
;
211 char *temp_string
=NULL
;
212 char *quote_string
=NULL
;
216 char *conv
= "12345678";
219 setlocale (LC_ALL
, "");
220 bindtextdomain (PACKAGE
, LOCALEDIR
);
221 textdomain (PACKAGE
);
223 labels
= malloc (labels_size
* sizeof(*labels
));
224 unitv
= malloc (unitv_size
* sizeof(*unitv
));
225 thlds
= malloc (thlds_size
* sizeof(*thlds
));
226 response_value
= malloc (response_size
* sizeof(*response_value
));
227 previous_value
= malloc (previous_size
* sizeof(*previous_value
));
228 eval_method
= calloc (eval_size
, sizeof(*eval_method
));
229 oids
= calloc(oids_size
, sizeof (char *));
231 label
= strdup ("SNMP");
233 port
= strdup (DEFAULT_PORT
);
234 outbuff
= strdup ("");
235 delimiter
= strdup (" = ");
236 output_delim
= strdup (DEFAULT_OUTPUT_DELIMITER
);
237 timeout_interval
= DEFAULT_SOCKET_TIMEOUT
;
238 retries
= DEFAULT_RETRIES
;
240 np_init( (char *) progname
, argc
, argv
);
242 /* Parse extra opts if any */
243 argv
=np_extra_opts (&argc
, argv
, progname
);
245 np_set_args(argc
, argv
);
249 if (process_arguments (argc
, argv
) == ERROR
)
250 usage4 (_("Could not parse arguments"));
253 if (!strcmp(label
, "SNMP"))
254 label
= strdup("SNMP RATE");
258 previous_state
= np_state_read();
259 if(previous_state
!=NULL
) {
260 /* Split colon separated values */
261 previous_string
= strdup((char *) previous_state
->data
);
262 while((ap
= strsep(&previous_string
, ":")) != NULL
) {
264 printf("State for %zd=%s\n", i
, ap
);
265 while (i
>= previous_size
) {
266 previous_size
+= OID_COUNT_STEP
;
267 previous_value
= realloc(previous_value
, previous_size
* sizeof(*previous_value
));
269 previous_value
[i
++]=strtod(ap
,NULL
);
274 /* Populate the thresholds */
275 th_warn
=warning_thresholds
;
276 th_crit
=critical_thresholds
;
277 for (size_t i
= 0; i
< numoids
; i
++) {
278 char *w
= th_warn
? strndup(th_warn
, strcspn(th_warn
, ",")) : NULL
;
279 char *c
= th_crit
? strndup(th_crit
, strcspn(th_crit
, ",")) : NULL
;
280 /* translate "2:1" to "@1:2" for backwards compatibility */
281 w
= w
? fix_snmp_range(w
) : NULL
;
282 c
= c
? fix_snmp_range(c
) : NULL
;
284 while (i
>= thlds_size
) {
285 thlds_size
+= OID_COUNT_STEP
;
286 thlds
= realloc(thlds
, thlds_size
* sizeof(*thlds
));
289 /* Skip empty thresholds, while avoiding segfault */
290 set_thresholds(&thlds
[i
],
291 w
? strpbrk(w
, NP_THRESHOLDS_CHARS
) : NULL
,
292 c
? strpbrk(c
, NP_THRESHOLDS_CHARS
) : NULL
);
294 th_warn
=strchr(th_warn
, ',');
295 if (th_warn
) th_warn
++;
299 th_crit
=strchr(th_crit
, ',');
300 if (th_crit
) th_crit
++;
305 /* Create the command array to execute */
307 snmpcmd
= strdup (PATH_TO_SNMPGETNEXT
);
309 snmpcmd
= strdup (PATH_TO_SNMPGET
);
312 /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */
315 command_line
= calloc (11 + numcontext
+ numauthpriv
+ 1 + numoids
+ 1, sizeof (char *));
317 command_line
[index
++] = snmpcmd
;
318 command_line
[index
++] = strdup ("-Le");
319 command_line
[index
++] = strdup ("-t");
320 xasprintf (&command_line
[index
++], "%d", timeout_interval
);
321 command_line
[index
++] = strdup ("-r");
322 xasprintf (&command_line
[index
++], "%d", retries
);
323 command_line
[index
++] = strdup ("-m");
324 command_line
[index
++] = strdup (miblist
);
325 command_line
[index
++] = "-v";
326 command_line
[index
++] = strdup (proto
);
328 xasprintf(&cl_hidden_auth
, "%s -Le -t %d -r %d -m %s -v %s",
329 snmpcmd
, timeout_interval
, retries
, strlen(miblist
) ? miblist
: "''", proto
);
331 if (ignore_mib_parsing_errors
) {
332 command_line
[index
++] = "-Pe";
333 xasprintf(&cl_hidden_auth
, "%s -Pe", cl_hidden_auth
);
337 for (int i
= 0; i
< numcontext
; i
++) {
338 command_line
[index
++] = contextargs
[i
];
341 for (int i
= 0; i
< numauthpriv
; i
++) {
342 command_line
[index
++] = authpriv
[i
];
345 xasprintf (&command_line
[index
++], "%s:%s", server_address
, port
);
347 xasprintf(&cl_hidden_auth
, "%s [context] [authpriv] %s:%s",
352 for (size_t i
= 0; i
< numoids
; i
++) {
353 command_line
[index
++] = oids
[i
];
354 xasprintf(&cl_hidden_auth
, "%s %s", cl_hidden_auth
, oids
[i
]);
357 command_line
[index
++] = NULL
;
360 printf ("%s\n", cl_hidden_auth
);
363 /* Set signal handling and alarm */
364 if (signal (SIGALRM
, runcmd_timeout_alarm_handler
) == SIG_ERR
) {
365 usage4 (_("Cannot catch SIGALRM"));
367 alarm(timeout_interval
* retries
+ 5);
369 /* Run the command */
370 return_code
= cmd_run_array (command_line
, &chld_out
, &chld_err
, 0);
372 /* disable alarm again */
375 /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs,
376 only return state unknown if return code is non zero or there is no stdout.
377 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
379 if (return_code
!= 0)
381 if (chld_out
.lines
== 0)
383 if (external_error
) {
384 if (chld_err
.lines
> 0) {
385 printf (_("External command error: %s\n"), chld_err
.line
[0]);
386 for (size_t i
= 1; i
< chld_err
.lines
; i
++) {
387 printf ("%s\n", chld_err
.line
[i
]);
390 printf(_("External command error with no output (return code: %d)\n"), return_code
);
392 exit (STATE_UNKNOWN
);
396 for (size_t i
= 0; i
< chld_out
.lines
; i
++) {
397 printf ("%s\n", chld_out
.line
[i
]);
403 for (size_t i
= 0; line
< chld_out
.lines
&& i
< numoids
; line
++, i
++, total_oids
++) {
409 ptr
= chld_out
.line
[line
];
410 oidname
= strpcpy (oidname
, ptr
, delimiter
);
411 response
= strstr (ptr
, delimiter
);
412 if (response
== NULL
)
416 printf("Processing oid %zi (line %zi)\n oidname: %s\n response: %s\n", i
+1, line
+1, oidname
, response
);
419 /* Clean up type array - Sol10 does not necessarily zero it out */
420 bzero(type
, sizeof(type
));
423 /* We strip out the datatype indicator for PHBs */
424 if (strstr (response
, "Gauge: ")) {
425 show
= multiply (strstr (response
, "Gauge: ") + 7);
427 else if (strstr (response
, "Gauge32: ")) {
428 show
= multiply (strstr (response
, "Gauge32: ") + 9);
430 else if (strstr (response
, "Counter32: ")) {
431 show
= strstr (response
, "Counter32: ") + 11;
436 else if (strstr (response
, "Counter64: ")) {
437 show
= strstr (response
, "Counter64: ") + 11;
442 else if (strstr (response
, "INTEGER: ")) {
443 show
= multiply (strstr (response
, "INTEGER: ") + 9);
449 else if (strstr (response
, "OID: ")) {
450 show
= strstr (response
, "OID: ") + 5;
452 else if (strstr (response
, "STRING: ")) {
453 show
= strstr (response
, "STRING: ") + 8;
456 /* Get the rest of the string on multi-line strings */
458 COUNT_SEQ(ptr
, bk_count
, dq_count
)
459 while (dq_count
&& ptr
[0] != '\n' && ptr
[0] != '\0') {
461 GOBBLE_TOS(ptr
, "\n\"\\")
462 COUNT_SEQ(ptr
, bk_count
, dq_count
)
465 if (dq_count
) { /* unfinished line */
466 /* copy show verbatim first */
467 if (!mult_resp
) mult_resp
= strdup("");
468 xasprintf (&mult_resp
, "%s%s:\n%s\n", mult_resp
, oids
[i
], show
);
469 /* then strip out unmatched double-quote from single-line output */
470 if (show
[0] == '"') show
++;
472 /* Keep reading until we match end of double-quoted string */
473 for (line
++; line
< chld_out
.lines
; line
++) {
474 ptr
= chld_out
.line
[line
];
475 xasprintf (&mult_resp
, "%s%s\n", mult_resp
, ptr
);
477 COUNT_SEQ(ptr
, bk_count
, dq_count
)
478 while (dq_count
&& ptr
[0] != '\n' && ptr
[0] != '\0') {
480 GOBBLE_TOS(ptr
, "\n\"\\")
481 COUNT_SEQ(ptr
, bk_count
, dq_count
)
483 /* Break for loop before next line increment when done */
484 if (!dq_count
) break;
489 else if (strstr (response
, "Timeticks: ")) {
490 show
= strstr (response
, "Timeticks: ");
495 iresult
= STATE_DEPENDENT
;
497 /* Process this block for numeric comparisons */
498 /* Make some special values,like Timeticks numeric only if a threshold is defined */
499 if (thlds
[i
]->warning
|| thlds
[i
]->critical
|| calculate_rate
) {
501 print_thresholds(" thresholds", thlds
[i
]);
503 ptr
= strpbrk (show
, "-0123456789");
506 die (STATE_UNKNOWN
,_("No valid data returned (%s)\n"), show
);
507 else if (nulloid
== 0)
508 die (STATE_OK
,_("No valid data returned (%s)\n"), show
);
509 else if (nulloid
== 1)
510 die (STATE_WARNING
,_("No valid data returned (%s)\n"), show
);
511 else if (nulloid
== 2)
512 die (STATE_CRITICAL
,_("No valid data returned (%s)\n"), show
);
514 while (i
>= response_size
) {
515 response_size
+= OID_COUNT_STEP
;
516 response_value
= realloc(response_value
, response_size
* sizeof(*response_value
));
518 response_value
[i
] = strtod (ptr
, NULL
) + offset
;
521 if (previous_state
!=NULL
) {
522 duration
= current_time
-previous_state
->time
;
524 die(STATE_UNKNOWN
,_("Time duration between plugin calls is invalid"));
525 temp_double
= response_value
[i
]-previous_value
[i
];
526 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
528 if(temp_double
<(double)0.0)
529 temp_double
+=(double)4294967296.0; /* 2^32 */
530 if(temp_double
<(double)0.0)
531 temp_double
+=(double)18446744069414584320.0; /* 2^64-2^32 */;
533 /* Convert to per second, then use multiplier */
534 temp_double
= temp_double
/duration
*rate_multiplier
;
535 iresult
= get_status(temp_double
, thlds
[i
]);
536 xasprintf (&show
, conv
, temp_double
);
539 iresult
= get_status(response_value
[i
], thlds
[i
]);
540 xasprintf (&show
, conv
, response_value
[i
]);
544 /* Process this block for string matching */
545 else if (eval_size
> i
&& eval_method
[i
] & CRIT_STRING
) {
546 if (strcmp (show
, string_value
))
547 iresult
= (invert_search
==0) ? STATE_CRITICAL
: STATE_OK
;
549 iresult
= (invert_search
==0) ? STATE_OK
: STATE_CRITICAL
;
552 /* Process this block for regex matching */
553 else if (eval_size
> i
&& eval_method
[i
] & CRIT_REGEX
) {
554 excode
= regexec (&preg
, response
, 10, pmatch
, eflags
);
556 iresult
= (invert_search
==0) ? STATE_OK
: STATE_CRITICAL
;
558 else if (excode
!= REG_NOMATCH
) {
559 regerror (excode
, &preg
, errbuf
, MAX_INPUT_BUFFER
);
560 printf (_("Execute Error: %s\n"), errbuf
);
561 exit (STATE_CRITICAL
);
564 iresult
= (invert_search
==0) ? STATE_CRITICAL
: STATE_OK
;
568 /* Process this block for existence-nonexistence checks */
569 /* TV: Should this be outside of this else block? */
571 if (eval_size
> i
&& eval_method
[i
] & CRIT_PRESENT
)
572 iresult
= STATE_CRITICAL
;
573 else if (eval_size
> i
&& eval_method
[i
] & WARN_PRESENT
)
574 iresult
= STATE_WARNING
;
575 else if (response
&& iresult
== STATE_DEPENDENT
)
579 /* Result is the worst outcome of all the OIDs tested */
580 result
= max_state (result
, iresult
);
582 /* Prepend a label for this OID if there is one */
583 if (nlabels
>= (size_t)1 && (size_t)i
< nlabels
&& labels
[i
] != NULL
)
584 xasprintf (&outbuff
, "%s%s%s %s%s%s", outbuff
,
585 (i
== 0) ? " " : output_delim
,
586 labels
[i
], mark (iresult
), show
, mark (iresult
));
588 xasprintf (&outbuff
, "%s%s%s%s%s", outbuff
, (i
== 0) ? " " : output_delim
,
589 mark (iresult
), show
, mark (iresult
));
591 /* Append a unit string for this OID if there is one */
592 if (nunits
> (size_t)0 && (size_t)i
< nunits
&& unitv
[i
] != NULL
)
593 xasprintf (&outbuff
, "%s %s", outbuff
, unitv
[i
]);
595 /* Write perfdata with whatever can be parsed by strtod, if possible */
599 if (perf_labels
&& nlabels
>= (size_t)1 && (size_t)i
< nlabels
&& labels
[i
] != NULL
)
600 temp_string
=labels
[i
];
603 if (strpbrk (temp_string
, " ='\"") == NULL
) {
604 strncat(perfstr
, temp_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
606 if (strpbrk (temp_string
, "'") == NULL
) {
611 strncat(perfstr
, quote_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
612 strncat(perfstr
, temp_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
613 strncat(perfstr
, quote_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
615 strncat(perfstr
, "=", sizeof(perfstr
)-strlen(perfstr
)-1);
616 len
= sizeof(perfstr
)-strlen(perfstr
)-1;
617 strncat(perfstr
, show
, len
>ptr
-show
? ptr
-show
: len
);
619 if (strcmp(type
, "") != 0) {
620 strncat(perfstr
, type
, sizeof(perfstr
)-strlen(perfstr
)-1);
623 if (warning_thresholds
) {
624 strncat(perfstr
, ";", sizeof(perfstr
)-strlen(perfstr
)-1);
625 if(thlds
[i
]->warning
&& thlds
[i
]->warning
->text
)
626 strncat(perfstr
, thlds
[i
]->warning
->text
, sizeof(perfstr
)-strlen(perfstr
)-1);
629 if (critical_thresholds
) {
630 if (!warning_thresholds
)
631 strncat(perfstr
, ";", sizeof(perfstr
)-strlen(perfstr
)-1);
632 strncat(perfstr
, ";", sizeof(perfstr
)-strlen(perfstr
)-1);
633 if(thlds
[i
]->critical
&& thlds
[i
]->critical
->text
)
634 strncat(perfstr
, thlds
[i
]->critical
->text
, sizeof(perfstr
)-strlen(perfstr
)-1);
637 strncat(perfstr
, " ", sizeof(perfstr
)-strlen(perfstr
)-1);
641 /* Save state data, as all data collected now */
644 state_string
=malloc(string_length
);
645 if(state_string
==NULL
)
646 die(STATE_UNKNOWN
, _("Cannot malloc"));
649 for(int i
= 0; i
< total_oids
; i
++) {
650 xasprintf(&temp_string
,"%.0f",response_value
[i
]);
651 if(temp_string
==NULL
)
652 die(STATE_UNKNOWN
,_("Cannot asprintf()"));
653 response_length
= strlen(temp_string
);
654 if(current_length
+response_length
>string_length
) {
655 string_length
=current_length
+1024;
656 state_string
=realloc(state_string
,string_length
);
657 if(state_string
==NULL
)
658 die(STATE_UNKNOWN
, _("Cannot realloc()"));
660 strcpy(&state_string
[current_length
],temp_string
);
661 current_length
=current_length
+response_length
;
662 state_string
[current_length
]=':';
666 state_string
[--current_length
]='\0';
668 printf("State string=%s\n",state_string
);
670 /* This is not strictly the same as time now, but any subtle variations will cancel out */
671 np_state_write_string(current_time
, state_string
);
672 if(previous_state
==NULL
) {
673 /* Or should this be highest state? */
674 die( STATE_OK
, _("No previous data to calculate rate - assume okay" ) );
678 printf ("%s %s -%s %s\n", label
, state_text (result
), outbuff
, perfstr
);
679 if (mult_resp
) printf ("%s", mult_resp
);
686 /* process command-line arguments */
688 process_arguments (int argc
, char **argv
)
692 size_t j
= 0, jj
= 0;
695 static struct option longopts
[] = {
697 {"community", required_argument
, 0, 'C'},
698 {"oid", required_argument
, 0, 'o'},
699 {"object", required_argument
, 0, 'o'},
700 {"delimiter", required_argument
, 0, 'd'},
701 {"nulloid", required_argument
, 0, 'z'},
702 {"output-delimiter", required_argument
, 0, 'D'},
703 {"string", required_argument
, 0, 's'},
704 {"timeout", required_argument
, 0, 't'},
705 {"regex", required_argument
, 0, 'r'},
706 {"ereg", required_argument
, 0, 'r'},
707 {"eregi", required_argument
, 0, 'R'},
708 {"label", required_argument
, 0, 'l'},
709 {"units", required_argument
, 0, 'u'},
710 {"port", required_argument
, 0, 'p'},
711 {"retries", required_argument
, 0, 'e'},
712 {"miblist", required_argument
, 0, 'm'},
713 {"protocol", required_argument
, 0, 'P'},
714 {"context", required_argument
, 0, 'N'},
715 {"seclevel", required_argument
, 0, 'L'},
716 {"secname", required_argument
, 0, 'U'},
717 {"authproto", required_argument
, 0, 'a'},
718 {"privproto", required_argument
, 0, 'x'},
719 {"authpasswd", required_argument
, 0, 'A'},
720 {"privpasswd", required_argument
, 0, 'X'},
721 {"next", no_argument
, 0, 'n'},
722 {"rate", no_argument
, 0, L_CALCULATE_RATE
},
723 {"rate-multiplier", required_argument
, 0, L_RATE_MULTIPLIER
},
724 {"offset", required_argument
, 0, L_OFFSET
},
725 {"invert-search", no_argument
, 0, L_INVERT_SEARCH
},
726 {"perf-oids", no_argument
, 0, 'O'},
727 {"ipv4", no_argument
, 0, '4'},
728 {"ipv6", no_argument
, 0, '6'},
729 {"multiplier", required_argument
, 0, 'M'},
730 {"fmtstr", required_argument
, 0, 'f'},
731 {"ignore-mib-parsing-errors", no_argument
, false, L_IGNORE_MIB_PARSING_ERRORS
},
738 /* reverse compatibility for very old non-POSIX usage forms */
739 for (c
= 1; c
< argc
; c
++) {
740 if (strcmp ("-to", argv
[c
]) == 0)
741 strcpy (argv
[c
], "-t");
742 if (strcmp ("-wv", argv
[c
]) == 0)
743 strcpy (argv
[c
], "-w");
744 if (strcmp ("-cv", argv
[c
]) == 0)
745 strcpy (argv
[c
], "-c");
749 c
= getopt_long (argc
, argv
, "nhvVO46t:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:N:L:U:a:x:A:X:M:f:z:",
752 if (c
== -1 || c
== EOF
)
756 case '?': /* usage */
760 exit (STATE_UNKNOWN
);
761 case 'V': /* version */
762 print_revision (progname
, NP_VERSION
);
763 exit (STATE_UNKNOWN
);
764 case 'v': /* verbose */
768 /* Connection info */
769 case 'C': /* group or community */
772 case 'H': /* Host or server */
773 server_address
= optarg
;
775 case 'p': /* TCP port number */
778 case 'm': /* List of MIBS */
781 case 'n': /* usesnmpgetnext */
782 usesnmpgetnext
= true;
784 case 'P': /* SNMP protocol version */
787 case 'N': /* SNMPv3 context */
790 case 'L': /* security level */
793 case 'U': /* security username */
796 case 'a': /* auth protocol */
799 case 'x': /* priv protocol */
802 case 'A': /* auth passwd */
805 case 'X': /* priv passwd */
808 case 't': /* timeout period */
809 if (!is_integer (optarg
))
810 usage2 (_("Timeout interval must be a positive integer"), optarg
);
812 timeout_interval
= atoi (optarg
);
815 /* Test parameters */
816 case 'c': /* critical threshold */
817 critical_thresholds
= optarg
;
819 case 'w': /* warning threshold */
820 warning_thresholds
= optarg
;
822 case 'e': /* PRELIMINARY - may change */
823 case 'E': /* PRELIMINARY - may change */
824 if (!is_integer (optarg
))
825 usage2 (_("Retries interval must be a positive integer"), optarg
);
827 retries
= atoi(optarg
);
829 case 'o': /* object identifier */
830 if ( strspn( optarg
, "0123456789.," ) != strlen( optarg
) ) {
832 * we have something other than digits, periods and comas,
833 * so we have a mib variable, rather than just an SNMP OID,
834 * so we have to actually read the mib files
838 for (ptr
= strtok(optarg
, ", "); ptr
!= NULL
; ptr
= strtok(NULL
, ", "), j
++) {
839 while (j
>= oids_size
) {
840 oids_size
+= OID_COUNT_STEP
;
841 oids
= realloc(oids
, oids_size
* sizeof (*oids
));
843 oids
[j
] = strdup(ptr
);
846 if (c
== 'E' || c
== 'e') {
848 while (j
+1 >= eval_size
) {
849 eval_size
+= OID_COUNT_STEP
;
850 eval_method
= realloc(eval_method
, eval_size
* sizeof(*eval_method
));
851 memset(eval_method
+ eval_size
- OID_COUNT_STEP
, 0, 8);
854 eval_method
[j
+1] |= WARN_PRESENT
;
856 eval_method
[j
+1] |= CRIT_PRESENT
;
859 case 'z': /* Null OID Return Check */
860 if (!is_integer (optarg
))
861 usage2 (_("Exit status must be a positive integer"), optarg
);
863 nulloid
= atoi(optarg
);
865 case 's': /* string or substring */
866 strncpy (string_value
, optarg
, sizeof (string_value
) - 1);
867 string_value
[sizeof (string_value
) - 1] = 0;
868 while (jj
>= eval_size
) {
869 eval_size
+= OID_COUNT_STEP
;
870 eval_method
= realloc(eval_method
, eval_size
* sizeof(*eval_method
));
871 memset(eval_method
+ eval_size
- OID_COUNT_STEP
, 0, 8);
873 eval_method
[jj
++] = CRIT_STRING
;
875 case 'R': /* regex */
878 case 'r': /* regex */
879 cflags
|= REG_EXTENDED
| REG_NOSUB
| REG_NEWLINE
;
880 strncpy (regex_expect
, optarg
, sizeof (regex_expect
) - 1);
881 regex_expect
[sizeof (regex_expect
) - 1] = 0;
882 errcode
= regcomp (&preg
, regex_expect
, cflags
);
884 regerror (errcode
, &preg
, errbuf
, MAX_INPUT_BUFFER
);
885 printf (_("Could Not Compile Regular Expression"));
888 while (jj
>= eval_size
) {
889 eval_size
+= OID_COUNT_STEP
;
890 eval_method
= realloc(eval_method
, eval_size
* sizeof(*eval_method
));
891 memset(eval_method
+ eval_size
- OID_COUNT_STEP
, 0, 8);
893 eval_method
[jj
++] = CRIT_REGEX
;
897 case 'd': /* delimiter */
898 delimiter
= strscpy (delimiter
, optarg
);
900 case 'D': /* output-delimiter */
901 output_delim
= strscpy (output_delim
, optarg
);
903 case 'l': /* label */
905 if (nlabels
> labels_size
) {
907 labels
= realloc (labels
, labels_size
* sizeof(*labels
));
909 die (STATE_UNKNOWN
, _("Could not reallocate labels[%d]"), (int)nlabels
);
911 labels
[nlabels
- 1] = optarg
;
912 ptr
= thisarg (optarg
);
913 labels
[nlabels
- 1] = ptr
;
915 labels
[nlabels
- 1] = ptr
+ 1;
916 while (ptr
&& (ptr
= nextarg (ptr
))) {
918 if (nlabels
> labels_size
) {
920 labels
= realloc (labels
, labels_size
* sizeof(*labels
));
922 die (STATE_UNKNOWN
, _("Could not reallocate labels\n"));
926 labels
[nlabels
- 1] = ptr
+ 1;
928 labels
[nlabels
- 1] = ptr
;
931 case 'u': /* units */
934 if (nunits
> unitv_size
) {
936 unitv
= realloc (unitv
, unitv_size
* sizeof(*unitv
));
938 die (STATE_UNKNOWN
, _("Could not reallocate units [%d]\n"), (int)nunits
);
940 unitv
[nunits
- 1] = optarg
;
941 ptr
= thisarg (optarg
);
942 unitv
[nunits
- 1] = ptr
;
944 unitv
[nunits
- 1] = ptr
+ 1;
945 while (ptr
&& (ptr
= nextarg (ptr
))) {
946 if (nunits
> unitv_size
) {
948 unitv
= realloc (unitv
, unitv_size
* sizeof(*unitv
));
950 die (STATE_UNKNOWN
, _("Could not realloc() units\n"));
955 unitv
[nunits
- 1] = ptr
+ 1;
957 unitv
[nunits
- 1] = ptr
;
960 case L_CALCULATE_RATE
:
961 if(calculate_rate
==0)
962 np_enable_state(NULL
, 1);
965 case L_RATE_MULTIPLIER
:
966 if(!is_integer(optarg
)||((rate_multiplier
=atoi(optarg
))<=0))
967 usage2(_("Rate multiplier must be a positive integer"),optarg
);
970 offset
=strtod(optarg
,NULL
);
972 case L_INVERT_SEARCH
:
981 xasprintf(&ip_version
, "udp6:");
983 printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n");
986 if ( strspn( optarg
, "0123456789.," ) == strlen( optarg
) ) {
987 multiplier
=strtod(optarg
,NULL
);
991 if (multiplier
!= 1.0) {
996 case L_IGNORE_MIB_PARSING_ERRORS
:
997 ignore_mib_parsing_errors
= true;
1001 if (server_address
== NULL
)
1002 server_address
= argv
[optind
];
1004 if (community
== NULL
)
1005 community
= strdup (DEFAULT_COMMUNITY
);
1007 return validate_arguments ();
1011 /******************************************************************************
1015 <title>validate_arguments</title>
1017 <para>&PROTO_validate_arguments;</para>
1019 <para>Checks to see if the default miblist needs to be loaded. Also verifies
1020 the authentication and authorization combinations based on protocol version
1027 ******************************************************************************/
1032 validate_arguments ()
1034 /* check whether to load locally installed MIBS (CPU/disk intensive) */
1035 if (miblist
== NULL
) {
1037 miblist
= strdup (DEFAULT_MIBLIST
);
1039 miblist
= ""; /* don't read any mib files for numeric oids */
1043 /* Check server_address is given */
1044 if (server_address
== NULL
)
1045 die(STATE_UNKNOWN
, _("No host specified\n"));
1047 /* Check oid is given */
1049 die(STATE_UNKNOWN
, _("No OIDs specified\n"));
1052 xasprintf(&proto
, DEFAULT_PROTOCOL
);
1054 if ((strcmp(proto
,"1") == 0) || (strcmp(proto
, "2c")==0)) { /* snmpv1 or snmpv2c */
1056 authpriv
= calloc (numauthpriv
, sizeof (char *));
1057 authpriv
[0] = strdup ("-c");
1058 authpriv
[1] = strdup (community
);
1060 else if ( strcmp (proto
, "3") == 0 ) { /* snmpv3 args */
1061 if (!(context
== NULL
)) {
1063 contextargs
= calloc (numcontext
, sizeof (char *));
1064 contextargs
[0] = strdup ("-n");
1065 contextargs
[1] = strdup (context
);
1068 if (seclevel
== NULL
)
1069 xasprintf(&seclevel
, "noAuthNoPriv");
1071 if (secname
== NULL
)
1072 die(STATE_UNKNOWN
, _("Required parameter: %s\n"), "secname");
1074 if (strcmp(seclevel
, "noAuthNoPriv") == 0) {
1076 authpriv
= calloc (numauthpriv
, sizeof (char *));
1077 authpriv
[0] = strdup ("-l");
1078 authpriv
[1] = strdup ("noAuthNoPriv");
1079 authpriv
[2] = strdup ("-u");
1080 authpriv
[3] = strdup (secname
);
1082 if (! ( (strcmp(seclevel
, "authNoPriv")==0) || (strcmp(seclevel
, "authPriv")==0) ) ) {
1083 usage2 (_("Invalid seclevel"), seclevel
);
1086 if (authproto
== NULL
)
1087 xasprintf(&authproto
, DEFAULT_AUTH_PROTOCOL
);
1089 if (authpasswd
== NULL
)
1090 die(STATE_UNKNOWN
, _("Required parameter: %s\n"), "authpasswd");
1092 if ( strcmp(seclevel
, "authNoPriv") == 0 ) {
1094 authpriv
= calloc (numauthpriv
, sizeof (char *));
1095 authpriv
[0] = strdup ("-l");
1096 authpriv
[1] = strdup ("authNoPriv");
1097 authpriv
[2] = strdup ("-a");
1098 authpriv
[3] = strdup (authproto
);
1099 authpriv
[4] = strdup ("-u");
1100 authpriv
[5] = strdup (secname
);
1101 authpriv
[6] = strdup ("-A");
1102 authpriv
[7] = strdup (authpasswd
);
1103 } else if ( strcmp(seclevel
, "authPriv") == 0 ) {
1104 if (privproto
== NULL
)
1105 xasprintf(&privproto
, DEFAULT_PRIV_PROTOCOL
);
1107 if (privpasswd
== NULL
)
1108 die(STATE_UNKNOWN
, _("Required parameter: %s\n"), "privpasswd");
1111 authpriv
= calloc (numauthpriv
, sizeof (char *));
1112 authpriv
[0] = strdup ("-l");
1113 authpriv
[1] = strdup ("authPriv");
1114 authpriv
[2] = strdup ("-a");
1115 authpriv
[3] = strdup (authproto
);
1116 authpriv
[4] = strdup ("-u");
1117 authpriv
[5] = strdup (secname
);
1118 authpriv
[6] = strdup ("-A");
1119 authpriv
[7] = strdup (authpasswd
);
1120 authpriv
[8] = strdup ("-x");
1121 authpriv
[9] = strdup (privproto
);
1122 authpriv
[10] = strdup ("-X");
1123 authpriv
[11] = strdup (privpasswd
);
1129 usage2 (_("Invalid SNMP version"), proto
);
1137 /* trim leading whitespace
1138 if there is a leading quote, make sure it balances */
1143 str
+= strspn (str
, " \t\r\n"); /* trim any leading whitespace */
1144 if (str
[0] == '\'') { /* handle SIMPLE quoted strings */
1145 if (strlen (str
) == 1 || !strstr (str
+ 1, "'"))
1146 die (STATE_UNKNOWN
, _("Unbalanced quotes\n"));
1153 /* if there's a leading quote, advance to the trailing quote
1154 set the trailing quote to '\x0'
1155 if the string continues, advance beyond the comma */
1160 if (str
[0] == '\'') {
1162 if (strlen (str
) > 1) {
1163 str
= strstr (str
+ 1, "'");
1170 if (str
[0] == ',') {
1172 if (strlen (str
) > 1) {
1179 if ((str
= strstr (str
, ",")) && strlen (str
) > 1) {
1188 /* multiply result (values 0 < n < 1 work as divider) */
1190 multiply (char *str
)
1200 printf(" multiply input: %s\n", str
);
1202 val
= strtod (str
, &endptr
);
1203 if ((val
== 0.0) && (endptr
== str
)) {
1204 die(STATE_UNKNOWN
, _("multiplier set (%.1f), but input is not a number: %s"), multiplier
, str
);
1208 printf(" multiply extracted double: %f\n", val
);
1213 if (val
== (int)val
) {
1214 snprintf(buffer
, DEFAULT_BUFFER_SIZE
, "%.0f", val
);
1217 printf(" multiply using format: %s\n", conv
);
1218 snprintf(buffer
, DEFAULT_BUFFER_SIZE
, conv
, val
);
1221 printf(" multiply result: %s\n", buffer
);
1229 print_revision (progname
, NP_VERSION
);
1231 printf (COPYRIGHT
, copyright
, email
);
1233 printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
1239 printf (UT_HELP_VRSN
);
1240 printf (UT_EXTRA_OPTS
);
1243 printf (UT_HOST_PORT
, 'p', DEFAULT_PORT
);
1245 /* SNMP and Authentication Protocol */
1246 printf (" %s\n", "-n, --next");
1247 printf (" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
1248 printf (" %s\n", "-P, --protocol=[1|2c|3]");
1249 printf (" %s\n", _("SNMP protocol version"));
1250 printf (" %s\n", "-N, --context=CONTEXT");
1251 printf (" %s\n", _("SNMPv3 context"));
1252 printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
1253 printf (" %s\n", _("SNMPv3 securityLevel"));
1254 printf (" %s\n", "-a, --authproto=AUTHENTICATION_PROTOCOL");
1255 printf (" %s\n", _("SNMPv3 authentication protocol (default MD5), available options depend on the specific version of the net-snmp tools"));
1256 printf (" %s\n", _("if < 5.8 SHA (1) and MD5 should be available, if >= 5.8 additionally SHA-224, SHA-256, SHA-384 and SHA-512"));
1257 printf (" %s\n", "-x, --privproto=PRIVACY_PROTOCOL");
1258 printf (" %s\n", _("SNMPv3 privacy protocol (default DES), available options depend on the specific version of the net-snmp tools"));
1259 printf (" %s\n", _("if < 5.8 DES and AES should be available, if >= 5.8 additionally AES-192 and AES-256"));
1261 /* Authentication Tokens*/
1262 printf (" %s\n", "-C, --community=STRING");
1263 printf (" %s ", _("Optional community string for SNMP communication"));
1264 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY
);
1265 printf (" %s\n", "-U, --secname=USERNAME");
1266 printf (" %s\n", _("SNMPv3 username"));
1267 printf (" %s\n", "-A, --authpasswd=PASSWORD");
1268 printf (" %s\n", _("SNMPv3 authentication password"));
1269 printf (" %s\n", "-X, --privpasswd=PASSWORD");
1270 printf (" %s\n", _("SNMPv3 privacy password"));
1273 printf (" %s\n", "-o, --oid=OID(s)");
1274 printf (" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
1275 printf (" %s\n", "-m, --miblist=STRING");
1276 printf (" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
1277 printf (" %s\n", _("for symbolic OIDs.)"));
1278 printf (" %s\n", "-d, --delimiter=STRING");
1279 printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER
);
1280 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1281 printf (" %s\n", _("to be the data that should be used in the evaluation."));
1282 printf (" %s\n", "-z, --nulloid=#");
1283 printf (" %s\n", _("If the check returns a 0 length string or NULL value"));
1284 printf (" %s\n", _("This option allows you to choose what status you want it to exit"));
1285 printf (" %s\n", _("Excluding this option renders the default exit of 3(STATE_UNKNOWN)"));
1286 printf (" %s\n", _("0 = OK"));
1287 printf (" %s\n", _("1 = WARNING"));
1288 printf (" %s\n", _("2 = CRITICAL"));
1289 printf (" %s\n", _("3 = UNKNOWN"));
1291 /* Tests Against Integers */
1292 printf (" %s\n", "-w, --warning=THRESHOLD(s)");
1293 printf (" %s\n", _("Warning threshold range(s)"));
1294 printf (" %s\n", "-c, --critical=THRESHOLD(s)");
1295 printf (" %s\n", _("Critical threshold range(s)"));
1296 printf (" %s\n", "--rate");
1297 printf (" %s\n", _("Enable rate calculation. See 'Rate Calculation' below"));
1298 printf (" %s\n", "--rate-multiplier");
1299 printf (" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
1300 printf (" %s\n", "--offset=OFFSET");
1301 printf (" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data"));
1303 /* Tests Against Strings */
1304 printf (" %s\n", "-s, --string=STRING");
1305 printf (" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
1306 printf (" %s\n", "-r, --ereg=REGEX");
1307 printf (" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
1308 printf (" %s\n", "-R, --eregi=REGEX");
1309 printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
1310 printf (" %s\n", "--invert-search");
1311 printf (" %s\n", _("Invert search result (CRITICAL if found)"));
1313 /* Output Formatting */
1314 printf (" %s\n", "-l, --label=STRING");
1315 printf (" %s\n", _("Prefix label for output from plugin"));
1316 printf (" %s\n", "-u, --units=STRING");
1317 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1318 printf (" %s\n", "-D, --output-delimiter=STRING");
1319 printf (" %s\n", _("Separates output on multiple OID requests"));
1320 printf (" %s\n", "-M, --multiplier=FLOAT");
1321 printf (" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1"));
1322 printf (" %s\n", "-f, --fmtstr=STRING");
1323 printf (" %s\n", _("C-style format string for float values (see option -M)"));
1325 printf (UT_CONN_TIMEOUT
, DEFAULT_SOCKET_TIMEOUT
);
1326 printf (" %s\n", _("NOTE the final timeout value is calculated using this formula: timeout_interval * retries + 5"));
1327 printf (" %s\n", "-e, --retries=INTEGER");
1328 printf (" %s%i\n", _("Number of retries to be used in the requests, default: "), DEFAULT_RETRIES
);
1330 printf (" %s\n", "-O, --perf-oids");
1331 printf (" %s\n", _("Label performance data with OIDs instead of --label's"));
1333 printf (" %s\n", "--ignore-mib-parsing-errors");
1334 printf (" %s\n", _("Tell snmpget to not print errors encountered when parsing MIB files"));
1336 printf (UT_VERBOSE
);
1339 printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
1340 printf ("%s\n", _("if you don't have the package installed, you will need to download it from"));
1341 printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1344 printf ("%s\n", _("Notes:"));
1345 printf (" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited "));
1346 printf (" %s\n", _("list (lists with internal spaces must be quoted)."));
1348 printf(" -%s", UT_THRESHOLDS_NOTES
);
1350 printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1351 printf (" %s\n", _("- Note that only one string and one regex may be checked at present"));
1352 printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1353 printf (" %s\n", _("returned from the SNMP query is an unsigned integer."));
1356 printf("%s\n", _("Rate Calculation:"));
1357 printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when"));
1358 printf(" %s\n", _("calculating the counter difference since the last check. check_snmp"));
1359 printf(" %s\n", _("saves the last state information in a file so that the rate per second"));
1360 printf(" %s\n", _("can be calculated. Use the --rate option to save state information."));
1361 printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK."));
1362 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
1363 printf(" %s\n", _("changing the arguments will create a new state file."));
1365 printf (UT_SUPPORT
);
1373 printf ("%s\n", _("Usage:"));
1374 printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname
);
1375 printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1376 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1377 printf ("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n");
1378 printf ("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n");
1379 printf ("[-M multiplier [-f format]]\n");