summaryrefslogtreecommitdiffstats
path: root/plugins/check_snmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_snmp.c')
-rw-r--r--plugins/check_snmp.c2080
1 files changed, 928 insertions, 1152 deletions
diff --git a/plugins/check_snmp.c b/plugins/check_snmp.c
index 90a04027..a5a7afe8 100644
--- a/plugins/check_snmp.c
+++ b/plugins/check_snmp.c
@@ -1,697 +1,397 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_snmp plugin 3 * Monitoring check_snmp plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_snmp plugin 10 * This file contains the check_snmp plugin
11* 11 *
12* Check status of remote machines and obtain system information via SNMP 12 * Check status of remote machines and obtain system information via SNMP
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 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 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 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 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/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_snmp"; 31const char *progname = "check_snmp";
32const char *copyright = "1999-2007"; 32const char *copyright = "1999-2024";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "./common.h"
36#include "runcmd.h" 36#include "./runcmd.h"
37#include "utils.h" 37#include "./utils.h"
38#include "utils_cmd.h" 38#include "../lib/states.h"
39 39
40#define DEFAULT_COMMUNITY "public" 40#include "../lib/utils_base.h"
41#define DEFAULT_PORT "161" 41#include "../lib/output.h"
42#define DEFAULT_MIBLIST "ALL" 42#include "check_snmp.d/check_snmp_helpers.h"
43#define DEFAULT_PROTOCOL "1" 43
44#define DEFAULT_RETRIES 5 44#include <bits/getopt_core.h>
45#include <bits/getopt_ext.h>
46#include <strings.h>
47#include <stdint.h>
48
49#include "check_snmp.d/config.h"
50#include <stdlib.h>
51#include <arpa/inet.h>
52#include <net-snmp/library/parse.h>
53#include <net-snmp/net-snmp-config.h>
54#include <net-snmp/net-snmp-includes.h>
55#include <net-snmp/library/snmp.h>
56#include <net-snmp/library/keytools.h>
57#include <net-snmp/library/snmp_api.h>
58#include <net-snmp/session_api.h>
59#include <net-snmp/definitions.h>
60#include <net-snmp/library/asn1.h>
61#include <net-snmp/mib_api.h>
62#include <net-snmp/library/snmp_impl.h>
63#include <string.h>
64#include "../gl/regex.h"
65#include "../gl/base64.h"
66#include <assert.h>
67
68const char DEFAULT_COMMUNITY[] = "public";
69const char DEFAULT_MIBLIST[] = "ALL";
45#define DEFAULT_AUTH_PROTOCOL "MD5" 70#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
50
51#define mark(a) ((a)!=0?"*":"")
52
53#define CHECK_UNDEF 0
54#define CRIT_PRESENT 1
55#define CRIT_STRING 2
56#define CRIT_REGEX 4
57#define WARN_PRESENT 8
58
59#define OID_COUNT_STEP 8
60
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
67
68/* Gobble to string - stop incrementing c when c[0] match one of the
69 * characters in s */
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)
72 * from c[0] */
73#define COUNT_SEQ(c, bk, dq) switch(c[0]) {\
74 case '\\': \
75 if (bk) bk--; \
76 else bk++; \
77 break; \
78 case '"': \
79 if (!dq) { dq++; } \
80 else if(!bk) { dq--; } \
81 else { bk--; } \
82 break; \
83 }
84
85
86 71
87static int process_arguments (int, char **); 72#ifdef HAVE_USM_DES_PRIV_PROTOCOL
88static int validate_arguments (void); 73# define DEFAULT_PRIV_PROTOCOL "DES"
89static char *thisarg (char *str); 74#else
90static char *nextarg (char *str); 75# define DEFAULT_PRIV_PROTOCOL "AES"
91void print_usage (void); 76#endif
92static void print_help (void); 77
93static char *multiply (char *str); 78typedef struct proces_arguments_wrapper {
94 79 int errorcode;
95#include "regex.h" 80 check_snmp_config config;
96static char regex_expect[MAX_INPUT_BUFFER] = ""; 81} process_arguments_wrapper;
97static regex_t preg; 82
98static regmatch_t pmatch[10]; 83static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
99static char errbuf[MAX_INPUT_BUFFER] = ""; 84static char *trim_whitespaces_and_check_quoting(char *str);
100static char perfstr[MAX_INPUT_BUFFER] = "| "; 85static char *get_next_argument(char *str);
101static int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 86void print_usage(void);
102static int eflags = 0; 87void print_help(void);
103static int errcode, excode; 88
104 89int verbose = 0;
105static char *server_address = NULL; 90
106static char *community = NULL; 91typedef struct {
107static char **contextargs = NULL; 92 int errorcode;
108static char *context = NULL; 93 char *state_string;
109static char **authpriv = NULL; 94} gen_state_string_type;
110static char *proto = NULL; 95gen_state_string_type gen_state_string(check_snmp_state_entry *entries, size_t num_of_entries) {
111static char *seclevel = NULL; 96 char *encoded_string = NULL;
112static char *secname = NULL; 97 gen_state_string_type result = {.errorcode = OK, .state_string = NULL};
113static char *authproto = NULL; 98
114static char *privproto = NULL; 99 if (verbose > 1) {
115static char *authpasswd = NULL; 100 printf("%s:\n", __FUNCTION__);
116static char *privpasswd = NULL; 101 for (size_t i = 0; i < num_of_entries; i++) {
117static int nulloid = STATE_UNKNOWN; 102 printf("Entry timestamp %lu: %s", entries[i].timestamp, ctime(&entries[i].timestamp));
118static char **oids = NULL; 103 switch (entries[i].type) {
119static size_t oids_size = 0; 104 case ASN_GAUGE:
120static char *label; 105 printf("Type GAUGE\n");
121static char *units; 106 break;
122static char *port; 107 case ASN_TIMETICKS:
123static char *snmpcmd; 108 printf("Type TIMETICKS\n");
124static char string_value[MAX_INPUT_BUFFER] = ""; 109 break;
125static int invert_search=0; 110 case ASN_COUNTER:
126static char **labels = NULL; 111 printf("Type COUNTER\n");
127static char **unitv = NULL; 112 break;
128static size_t nlabels = 0; 113 case ASN_UINTEGER:
129static size_t labels_size = OID_COUNT_STEP; 114 printf("Type UINTEGER\n");
130static size_t nunits = 0; 115 break;
131static size_t unitv_size = OID_COUNT_STEP; 116 case ASN_COUNTER64:
132static size_t numoids = 0; 117 printf("Type COUNTER64\n");
133static int numauthpriv = 0; 118 break;
134static int numcontext = 0; 119 case ASN_FLOAT:
135static int verbose = 0; 120 printf("Type FLOAT\n");
136static bool usesnmpgetnext = false; 121 case ASN_DOUBLE:
137static char *warning_thresholds = NULL; 122 printf("Type DOUBLE\n");
138static char *critical_thresholds = NULL; 123 break;
139static thresholds **thlds; 124 case ASN_INTEGER:
140static size_t thlds_size = OID_COUNT_STEP; 125 printf("Type INTEGER\n");
141static double *response_value; 126 break;
142static size_t response_size = OID_COUNT_STEP; 127 }
143static int retries = 0;
144static int *eval_method;
145static size_t eval_size = OID_COUNT_STEP;
146static char *delimiter;
147static char *output_delim;
148static char *miblist = NULL;
149static bool needmibs = false;
150static int calculate_rate = 0;
151static double offset = 0.0;
152static int rate_multiplier = 1;
153static state_data *previous_state;
154static double *previous_value;
155static size_t previous_size = OID_COUNT_STEP;
156static int perf_labels = 1;
157static char* ip_version = "";
158static double multiplier = 1.0;
159static char *fmtstr = "";
160static bool fmtstr_set = false;
161static char buffer[DEFAULT_BUFFER_SIZE];
162static bool ignore_mib_parsing_errors = false;
163
164static char *fix_snmp_range(char *th)
165{
166 double left, right;
167 char *colon, *ret;
168
169 if ((colon = strchr(th, ':')) == NULL || *(colon + 1) == '\0')
170 return th;
171
172 left = strtod(th, NULL);
173 right = strtod(colon + 1, NULL);
174 if (right >= left)
175 return th;
176
177 if ((ret = malloc(strlen(th) + 2)) == NULL)
178 die(STATE_UNKNOWN, _("Cannot malloc"));
179 *colon = '\0';
180 sprintf(ret, "@%s:%s", colon + 1, th);
181 free(th);
182 return ret;
183}
184
185int
186main (int argc, char **argv)
187{
188 int len, total_oids;
189 size_t line;
190 unsigned int bk_count = 0, dq_count = 0;
191 int iresult = STATE_UNKNOWN;
192 int result = STATE_UNKNOWN;
193 int return_code = 0;
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;
200 char *outbuff;
201 char *ptr = NULL;
202 char *show = NULL;
203 char *th_warn=NULL;
204 char *th_crit=NULL;
205 char type[8] = "";
206 output chld_out, chld_err;
207 char *previous_string=NULL;
208 char *ap=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;
213 time_t current_time;
214 double temp_double;
215 time_t duration;
216 char *conv = "12345678";
217 int is_counter=0;
218
219 setlocale (LC_ALL, "");
220 bindtextdomain (PACKAGE, LOCALEDIR);
221 textdomain (PACKAGE);
222
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 *));
230
231 label = strdup ("SNMP");
232 units = strdup ("");
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;
239
240 np_init( (char *) progname, argc, argv );
241
242 /* Parse extra opts if any */
243 argv=np_extra_opts (&argc, argv, progname);
244
245 np_set_args(argc, argv);
246
247 time(&current_time);
248 128
249 if (process_arguments (argc, argv) == ERROR) 129 switch (entries[i].type) {
250 usage4 (_("Could not parse arguments")); 130 case ASN_GAUGE:
251 131 case ASN_TIMETICKS:
252 if(calculate_rate) { 132 case ASN_COUNTER:
253 if (!strcmp(label, "SNMP")) 133 case ASN_UINTEGER:
254 label = strdup("SNMP RATE"); 134 case ASN_COUNTER64:
255 135 printf("Value %llu\n", entries[i].value.uIntVal);
256 size_t i = 0; 136 break;
257 137 case ASN_FLOAT:
258 previous_state = np_state_read(); 138 case ASN_DOUBLE:
259 if(previous_state!=NULL) { 139 printf("Value %f\n", entries[i].value.doubleVal);
260 /* Split colon separated values */ 140 break;
261 previous_string = strdup((char *) previous_state->data); 141 case ASN_INTEGER:
262 while((ap = strsep(&previous_string, ":")) != NULL) { 142 printf("Value %lld\n", entries[i].value.intVal);
263 if(verbose>2) 143 break;
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));
268 }
269 previous_value[i++]=strtod(ap,NULL);
270 } 144 }
271 } 145 }
272 } 146 }
273 147
274 /* Populate the thresholds */ 148 idx_t encoded = base64_encode_alloc((const char *)entries,
275 th_warn=warning_thresholds; 149 (idx_t)(num_of_entries * sizeof(check_snmp_state_entry)),
276 th_crit=critical_thresholds; 150 &encoded_string);
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;
283
284 while (i >= thlds_size) {
285 thlds_size += OID_COUNT_STEP;
286 thlds = realloc(thlds, thlds_size * sizeof(*thlds));
287 }
288 151
289 /* Skip empty thresholds, while avoiding segfault */ 152 if (encoded > 0 && encoded_string != NULL) {
290 set_thresholds(&thlds[i], 153 // success
291 w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL, 154 if (verbose > 1) {
292 c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL); 155 printf("encoded string: %s\n", encoded_string);
293 if (w) { 156 printf("encoded string length: %lu\n", strlen(encoded_string));
294 th_warn=strchr(th_warn, ',');
295 if (th_warn) th_warn++;
296 free(w);
297 }
298 if (c) {
299 th_crit=strchr(th_crit, ',');
300 if (th_crit) th_crit++;
301 free(c);
302 } 157 }
158 result.state_string = encoded_string;
159 return result;
303 } 160 }
161 result.errorcode = ERROR;
162 return result;
163}
304 164
305 /* Create the command array to execute */ 165typedef struct {
306 if(usesnmpgetnext) { 166 int errorcode;
307 snmpcmd = strdup (PATH_TO_SNMPGETNEXT); 167 check_snmp_state_entry *state;
308 }else{ 168} recover_state_data_type;
309 snmpcmd = strdup (PATH_TO_SNMPGET); 169recover_state_data_type recover_state_data(char *state_string, idx_t state_string_length) {
170 recover_state_data_type result = {.errorcode = OK, .state = NULL};
171
172 if (verbose > 1) {
173 printf("%s:\n", __FUNCTION__);
174 printf("State string: %s\n", state_string);
175 printf("State string length: %lu\n", state_string_length);
310 } 176 }
311 177
312 /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */ 178 idx_t outlen = 0;
179 bool decoded =
180 base64_decode_alloc(state_string, state_string_length, (char **)&result.state, &outlen);
313 181
314 unsigned index = 0; 182 if (!decoded) {
315 command_line = calloc (11 + numcontext + numauthpriv + 1 + numoids + 1, sizeof (char *)); 183 if (verbose) {
184 printf("Failed to decode state string\n");
185 }
186 // failure to decode
187 result.errorcode = ERROR;
188 return result;
189 }
316 190
317 command_line[index++] = snmpcmd; 191 if (result.state == NULL) {
318 command_line[index++] = strdup ("-Le"); 192 // Memory Error?
319 command_line[index++] = strdup ("-t"); 193 result.errorcode = ERROR;
320 xasprintf (&command_line[index++], "%d", timeout_interval); 194 return result;
321 command_line[index++] = strdup ("-r"); 195 }
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);
327 196
328 xasprintf(&cl_hidden_auth, "%s -Le -t %d -r %d -m %s -v %s", 197 if (verbose > 1) {
329 snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''", proto); 198 printf("Recovered %lu entries of size %lu\n",
199 (size_t)outlen / sizeof(check_snmp_state_entry), outlen);
200
201 for (size_t i = 0; i < (size_t)outlen / sizeof(check_snmp_state_entry); i++) {
202 printf("Entry timestamp %lu: %s", result.state[i].timestamp,
203 ctime(&result.state[i].timestamp));
204 switch (result.state[i].type) {
205 case ASN_GAUGE:
206 printf("Type GAUGE\n");
207 break;
208 case ASN_TIMETICKS:
209 printf("Type TIMETICKS\n");
210 break;
211 case ASN_COUNTER:
212 printf("Type COUNTER\n");
213 break;
214 case ASN_UINTEGER:
215 printf("Type UINTEGER\n");
216 break;
217 case ASN_COUNTER64:
218 printf("Type COUNTER64\n");
219 break;
220 case ASN_FLOAT:
221 printf("Type FLOAT\n");
222 case ASN_DOUBLE:
223 printf("Type DOUBLE\n");
224 break;
225 case ASN_INTEGER:
226 printf("Type INTEGER\n");
227 break;
228 }
330 229
331 if (ignore_mib_parsing_errors) { 230 switch (result.state[i].type) {
332 command_line[index++] = "-Pe"; 231 case ASN_GAUGE:
333 xasprintf(&cl_hidden_auth, "%s -Pe", cl_hidden_auth); 232 case ASN_TIMETICKS:
233 case ASN_COUNTER:
234 case ASN_UINTEGER:
235 case ASN_COUNTER64:
236 printf("Value %llu\n", result.state[i].value.uIntVal);
237 break;
238 case ASN_FLOAT:
239 case ASN_DOUBLE:
240 printf("Value %f\n", result.state[i].value.doubleVal);
241 break;
242 case ASN_INTEGER:
243 printf("Value %lld\n", result.state[i].value.intVal);
244 break;
245 }
246 }
334 } 247 }
335 248
249 return result;
250}
251
252int main(int argc, char **argv) {
253 setlocale(LC_ALL, "");
254 bindtextdomain(PACKAGE, LOCALEDIR);
255 textdomain(PACKAGE);
336 256
337 for (int i = 0; i < numcontext; i++) { 257 timeout_interval = DEFAULT_SOCKET_TIMEOUT;
338 command_line[index++] = contextargs[i];
339 }
340 258
341 for (int i = 0; i < numauthpriv; i++) { 259 np_init((char *)progname, argc, argv);
342 command_line[index++] = authpriv[i];
343 }
344 260
345 xasprintf (&command_line[index++], "%s:%s", server_address, port); 261 state_key stateKey = np_enable_state(NULL, 1, progname, argc, argv);
346 262
347 xasprintf(&cl_hidden_auth, "%s [context] [authpriv] %s:%s", 263 /* Parse extra opts if any */
348 cl_hidden_auth, 264 argv = np_extra_opts(&argc, argv, progname);
349 server_address,
350 port);
351 265
352 for (size_t i = 0; i < numoids; i++) { 266 np_set_args(argc, argv);
353 command_line[index++] = oids[i];
354 xasprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]);
355 }
356 267
357 command_line[index++] = NULL; 268 // Initialize net-snmp before touching the session we are going to use
269 init_snmp("check_snmp");
358 270
359 if (verbose) { 271 process_arguments_wrapper paw_tmp = process_arguments(argc, argv);
360 printf ("%s\n", cl_hidden_auth); 272 if (paw_tmp.errorcode == ERROR) {
273 usage4(_("Could not parse arguments"));
361 } 274 }
362 275
363 /* Set signal handling and alarm */ 276 check_snmp_config config = paw_tmp.config;
364 if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
365 usage4 (_("Cannot catch SIGALRM"));
366 }
367 alarm(timeout_interval * retries + 5);
368
369 /* Run the command */
370 return_code = cmd_run_array (command_line, &chld_out, &chld_err, 0);
371
372 /* disable alarm again */
373 alarm(0);
374
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
378 */
379 if (return_code != 0)
380 external_error=1;
381 if (chld_out.lines == 0)
382 external_error=1;
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]);
388 }
389 } else {
390 printf(_("External command error with no output (return code: %d)\n"), return_code);
391 }
392 exit (STATE_UNKNOWN);
393 }
394 277
395 if (verbose) { 278 if (config.output_format_is_set) {
396 for (size_t i = 0; i < chld_out.lines; i++) { 279 mp_set_format(config.output_format);
397 printf ("%s\n", chld_out.line[i]);
398 }
399 } 280 }
400 281
401 line = 0; 282 /* Set signal handling and alarm */
402 total_oids = 0; 283 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
403 for (size_t i = 0; line < chld_out.lines && i < numoids ; line++, i++, total_oids++) { 284 usage4(_("Cannot catch SIGALRM"));
404 if(calculate_rate) 285 }
405 conv = "%.10g";
406 else
407 conv = "%.0f";
408
409 ptr = chld_out.line[line];
410 oidname = strpcpy (oidname, ptr, delimiter);
411 response = strstr (ptr, delimiter);
412 if (response == NULL)
413 break;
414 286
415 if (verbose > 2) { 287 time_t current_time;
416 printf("Processing oid %zi (line %zi)\n oidname: %s\n response: %s\n", i+1, line+1, oidname, response); 288 time(&current_time);
417 }
418 289
419 /* Clean up type array - Sol10 does not necessarily zero it out */ 290 if (verbose > 2) {
420 bzero(type, sizeof(type)); 291 printf("current time: %s (timestamp: %lu)\n", ctime(&current_time), current_time);
292 }
421 293
422 is_counter=0; 294 snmp_responces response = do_snmp_query(config.snmp_params);
423 /* We strip out the datatype indicator for PHBs */
424 if (strstr (response, "Gauge: ")) {
425 show = multiply (strstr (response, "Gauge: ") + 7);
426 }
427 else if (strstr (response, "Gauge32: ")) {
428 show = multiply (strstr (response, "Gauge32: ") + 9);
429 }
430 else if (strstr (response, "Counter32: ")) {
431 show = strstr (response, "Counter32: ") + 11;
432 is_counter=1;
433 if(!calculate_rate)
434 strcpy(type, "c");
435 }
436 else if (strstr (response, "Counter64: ")) {
437 show = strstr (response, "Counter64: ") + 11;
438 is_counter=1;
439 if(!calculate_rate)
440 strcpy(type, "c");
441 }
442 else if (strstr (response, "INTEGER: ")) {
443 show = multiply (strstr (response, "INTEGER: ") + 9);
444 295
445 if (fmtstr_set) { 296 mp_check overall = mp_check_init();
446 conv = fmtstr;
447 }
448 }
449 else if (strstr (response, "OID: ")) {
450 show = strstr (response, "OID: ") + 5;
451 }
452 else if (strstr (response, "STRING: ")) {
453 show = strstr (response, "STRING: ") + 8;
454 conv = "%.10g";
455
456 /* Get the rest of the string on multi-line strings */
457 ptr = show;
458 COUNT_SEQ(ptr, bk_count, dq_count)
459 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
460 ptr++;
461 GOBBLE_TOS(ptr, "\n\"\\")
462 COUNT_SEQ(ptr, bk_count, dq_count)
463 }
464 297
465 if (dq_count) { /* unfinished line */ 298 if (response.errorcode == OK) {
466 /* copy show verbatim first */ 299 mp_subcheck sc_successfull_query = mp_subcheck_init();
467 if (!mult_resp) mult_resp = strdup(""); 300 xasprintf(&sc_successfull_query.output, "SNMP query was successful");
468 xasprintf (&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show); 301 sc_successfull_query = mp_set_subcheck_state(sc_successfull_query, STATE_OK);
469 /* then strip out unmatched double-quote from single-line output */ 302 mp_add_subcheck_to_check(&overall, sc_successfull_query);
470 if (show[0] == '"') show++; 303 } else {
471 304 // Error treatment here, either partial or whole
472 /* Keep reading until we match end of double-quoted string */ 305 mp_subcheck sc_failed_query = mp_subcheck_init();
473 for (line++; line < chld_out.lines; line++) { 306 xasprintf(&sc_failed_query.output, "SNMP query failed");
474 ptr = chld_out.line[line]; 307 sc_failed_query = mp_set_subcheck_state(sc_failed_query, STATE_OK);
475 xasprintf (&mult_resp, "%s%s\n", mult_resp, ptr); 308 mp_add_subcheck_to_check(&overall, sc_failed_query);
476 309 mp_exit(overall);
477 COUNT_SEQ(ptr, bk_count, dq_count) 310 }
478 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
479 ptr++;
480 GOBBLE_TOS(ptr, "\n\"\\")
481 COUNT_SEQ(ptr, bk_count, dq_count)
482 }
483 /* Break for loop before next line increment when done */
484 if (!dq_count) break;
485 }
486 }
487 311
488 } 312 check_snmp_state_entry *prev_state = NULL;
489 else if (strstr (response, "Timeticks: ")) { 313 bool have_previous_state = false;
490 show = strstr (response, "Timeticks: ");
491 }
492 else
493 show = response + 3;
494 314
495 iresult = STATE_DEPENDENT; 315 if (config.evaluation_params.calculate_rate) {
316 state_data *previous_state = np_state_read(stateKey);
317 if (previous_state == NULL) {
318 // failed to recover state
319 // or no previous state
320 have_previous_state = false;
321 } else {
322 // sanity check
323 recover_state_data_type prev_state_wrapper =
324 recover_state_data(previous_state->data, (idx_t)previous_state->length);
496 325
497 /* Process this block for numeric comparisons */ 326 if (prev_state_wrapper.errorcode == OK) {
498 /* Make some special values,like Timeticks numeric only if a threshold is defined */ 327 have_previous_state = true;
499 if (thlds[i]->warning || thlds[i]->critical || calculate_rate) { 328 prev_state = prev_state_wrapper.state;
500 if (verbose > 2) {
501 print_thresholds(" thresholds", thlds[i]);
502 }
503 ptr = strpbrk (show, "-0123456789");
504 if (ptr == NULL){
505 if (nulloid == 3)
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);
513 }
514 while (i >= response_size) {
515 response_size += OID_COUNT_STEP;
516 response_value = realloc(response_value, response_size * sizeof(*response_value));
517 }
518 response_value[i] = strtod (ptr, NULL) + offset;
519
520 if(calculate_rate) {
521 if (previous_state!=NULL) {
522 duration = current_time-previous_state->time;
523 if(duration<=0)
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) */
527 if(is_counter) {
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 */;
532 }
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);
537 }
538 } else { 329 } else {
539 iresult = get_status(response_value[i], thlds[i]); 330 have_previous_state = false;
540 xasprintf (&show, conv, response_value[i]); 331 prev_state = NULL;
541 } 332 }
542 } 333 }
334 }
543 335
544 /* Process this block for string matching */ 336 check_snmp_state_entry *new_state = NULL;
545 else if (eval_size > i && eval_method[i] & CRIT_STRING) { 337 if (config.evaluation_params.calculate_rate) {
546 if (strcmp (show, string_value)) 338 new_state = calloc(config.snmp_params.num_of_test_units, sizeof(check_snmp_state_entry));
547 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK; 339 if (new_state == NULL) {
548 else 340 die(STATE_UNKNOWN, "memory allocation failed");
549 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
550 } 341 }
342 }
551 343
552 /* Process this block for regex matching */ 344 // We got the the query results, now process them
553 else if (eval_size > i && eval_method[i] & CRIT_REGEX) { 345 for (size_t loop_index = 0; loop_index < config.snmp_params.num_of_test_units; loop_index++) {
554 excode = regexec (&preg, response, 10, pmatch, eflags); 346 if (verbose > 0) {
555 if (excode == 0) { 347 printf("loop_index: %zu\n", loop_index);
556 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
557 }
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);
562 }
563 else {
564 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
565 }
566 } 348 }
567 349
568 /* Process this block for existence-nonexistence checks */ 350 check_snmp_state_entry previous_unit_state = {};
569 /* TV: Should this be outside of this else block? */ 351 if (config.evaluation_params.calculate_rate && have_previous_state) {
570 else { 352 previous_unit_state = prev_state[loop_index];
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)
576 iresult = STATE_OK;
577 } 353 }
578 354
579 /* Result is the worst outcome of all the OIDs tested */ 355 check_snmp_evaluation single_eval =
580 result = max_state (result, iresult); 356 evaluate_single_unit(response.response_values[loop_index], config.evaluation_params,
581 357 config.snmp_params.test_units[loop_index], current_time,
582 /* Prepend a label for this OID if there is one */ 358 previous_unit_state, have_previous_state);
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));
587 else
588 xasprintf (&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim,
589 mark (iresult), show, mark (iresult));
590
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]);
594
595 /* Write perfdata with whatever can be parsed by strtod, if possible */
596 ptr = NULL;
597 strtod(show, &ptr);
598 if (ptr > show) {
599 if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
600 temp_string=labels[i];
601 else
602 temp_string=oidname;
603 if (strpbrk (temp_string, " ='\"") == NULL) {
604 strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1);
605 } else {
606 if (strpbrk (temp_string, "'") == NULL) {
607 quote_string="'";
608 } else {
609 quote_string="\"";
610 }
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);
614 }
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);
618
619 if (strcmp(type, "") != 0) {
620 strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1);
621 }
622
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);
627 }
628
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);
635 }
636 359
637 strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1); 360 if (config.evaluation_params.calculate_rate &&
361 mp_compute_subcheck_state(single_eval.sc) != STATE_UNKNOWN) {
362 new_state[loop_index] = single_eval.state;
638 } 363 }
639 }
640 364
641 /* Save state data, as all data collected now */ 365 mp_add_subcheck_to_check(&overall, single_eval.sc);
642 if(calculate_rate) {
643 string_length=1024;
644 state_string=malloc(string_length);
645 if(state_string==NULL)
646 die(STATE_UNKNOWN, _("Cannot malloc"));
647
648 current_length=0;
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()"));
659 }
660 strcpy(&state_string[current_length],temp_string);
661 current_length=current_length+response_length;
662 state_string[current_length]=':';
663 current_length++;
664 free(temp_string);
665 }
666 state_string[--current_length]='\0';
667 if (verbose > 2)
668 printf("State string=%s\n",state_string);
669
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" ) );
675 }
676 } 366 }
677 367
678 printf ("%s %s -%s %s\n", label, state_text (result), outbuff, perfstr); 368 if (config.evaluation_params.calculate_rate) {
679 if (mult_resp) printf ("%s", mult_resp); 369 // store state
370 gen_state_string_type current_state_wrapper =
371 gen_state_string(new_state, config.snmp_params.num_of_test_units);
680 372
681 return result; 373 if (current_state_wrapper.errorcode == OK) {
374 np_state_write_string(stateKey, current_time, current_state_wrapper.state_string);
375 } else {
376 die(STATE_UNKNOWN, "failed to create state string");
377 }
378 }
379 mp_exit(overall);
682} 380}
683 381
684
685
686/* process command-line arguments */ 382/* process command-line arguments */
687int 383static process_arguments_wrapper process_arguments(int argc, char **argv) {
688process_arguments (int argc, char **argv) 384 enum {
689{ 385 /* Longopts only arguments */
690 char *ptr; 386 invert_search_index = CHAR_MAX + 1,
691 int c = 1; 387 offset_index,
692 size_t j = 0, jj = 0; 388 ignore_mib_parsing_errors_index,
389 connection_prefix_index,
390 output_format_index,
391 calculate_rate,
392 rate_multiplier
393 };
693 394
694 int option = 0;
695 static struct option longopts[] = { 395 static struct option longopts[] = {
696 STD_LONG_OPTS, 396 STD_LONG_OPTS,
697 {"community", required_argument, 0, 'C'}, 397 {"community", required_argument, 0, 'C'},
@@ -719,662 +419,738 @@ process_arguments (int argc, char **argv)
719 {"authpasswd", required_argument, 0, 'A'}, 419 {"authpasswd", required_argument, 0, 'A'},
720 {"privpasswd", required_argument, 0, 'X'}, 420 {"privpasswd", required_argument, 0, 'X'},
721 {"next", no_argument, 0, 'n'}, 421 {"next", no_argument, 0, 'n'},
722 {"rate", no_argument, 0, L_CALCULATE_RATE}, 422 {"offset", required_argument, 0, offset_index},
723 {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER}, 423 {"invert-search", no_argument, 0, invert_search_index},
724 {"offset", required_argument, 0, L_OFFSET},
725 {"invert-search", no_argument, 0, L_INVERT_SEARCH},
726 {"perf-oids", no_argument, 0, 'O'}, 424 {"perf-oids", no_argument, 0, 'O'},
727 {"ipv4", no_argument, 0, '4'}, 425 {"ipv4", no_argument, 0, '4'},
728 {"ipv6", no_argument, 0, '6'}, 426 {"ipv6", no_argument, 0, '6'},
729 {"multiplier", required_argument, 0, 'M'}, 427 {"multiplier", required_argument, 0, 'M'},
730 {"fmtstr", required_argument, 0, 'f'}, 428 {"ignore-mib-parsing-errors", no_argument, 0, ignore_mib_parsing_errors_index},
731 {"ignore-mib-parsing-errors", no_argument, false, L_IGNORE_MIB_PARSING_ERRORS}, 429 {"connection-prefix", required_argument, 0, connection_prefix_index},
732 {0, 0, 0, 0} 430 {"output-format", required_argument, 0, output_format_index},
733 }; 431 {"rate", no_argument, 0, calculate_rate},
432 {"rate-multiplier", required_argument, 0, rate_multiplier},
433 {0, 0, 0, 0}};
434
435 if (argc < 2) {
436 process_arguments_wrapper result = {
437 .errorcode = ERROR,
438 };
439 return result;
440 }
441
442 // Count number of OIDs here first
443 int option = 0;
444 size_t oid_counter = 0;
445 while (true) {
446 int option_char = getopt_long(
447 argc, argv,
448 "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:", longopts, &option);
449
450 if (option_char == -1 || option_char == EOF) {
451 break;
452 }
453
454 switch (option_char) {
455 case 'o': {
456 // we are going to parse this again, so we work on a copy of that string
457 char *tmp_oids = strdup(optarg);
458 if (tmp_oids == NULL) {
459 die(STATE_UNKNOWN, "strdup failed");
460 }
461
462 for (char *ptr = strtok(tmp_oids, ", "); ptr != NULL;
463 ptr = strtok(NULL, ", "), oid_counter++) {
464 }
465 break;
466 }
467 case '?': /* usage */
468 usage5();
469 // fallthrough
470 case 'h': /* help */
471 print_help();
472 exit(STATE_UNKNOWN);
473 case 'V': /* version */
474 print_revision(progname, NP_VERSION);
475 exit(STATE_UNKNOWN);
476
477 default:
478 continue;
479 }
480 }
734 481
735 if (argc < 2) 482 /* Check whether at least one OID was given */
736 return ERROR; 483 if (oid_counter == 0) {
737 484 die(STATE_UNKNOWN, _("No OIDs specified\n"));
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");
746 } 485 }
747 486
748 while (1) { 487 // Allocate space for test units
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:", 488 check_snmp_test_unit *tmp = calloc(oid_counter, sizeof(check_snmp_test_unit));
750 longopts, &option); 489 if (tmp == NULL) {
490 die(STATE_UNKNOWN, "Failed to calloc");
491 }
492
493 for (size_t i = 0; i < oid_counter; i++) {
494 tmp[i] = check_snmp_test_unit_init();
495 }
751 496
752 if (c == -1 || c == EOF) 497 check_snmp_config config = check_snmp_config_init();
498 config.snmp_params.test_units = tmp;
499 config.snmp_params.num_of_test_units = oid_counter;
500
501 option = 0;
502 optind = 1; // Reset argument scanner
503 size_t tmp_oid_counter = 0;
504 size_t eval_counter = 0;
505 size_t unitv_counter = 0;
506 size_t labels_counter = 0;
507 unsigned char *authpasswd = NULL;
508 unsigned char *privpasswd = NULL;
509 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
510 char *port = NULL;
511 char *miblist = NULL;
512 char *connection_prefix = NULL;
513 bool snmp_version_set_explicitely = false;
514 // TODO error checking
515 while (true) {
516 int option_char = getopt_long(
517 argc, argv,
518 "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:", longopts, &option);
519
520 if (option_char == -1 || option_char == EOF) {
753 break; 521 break;
522 }
754 523
755 switch (c) { 524 switch (option_char) {
756 case '?': /* usage */ 525 case '?': /* usage */
757 usage5 (); 526 usage5();
758 case 'h': /* help */ 527 case 'h': /* help */
759 print_help (); 528 print_help();
760 exit (STATE_UNKNOWN); 529 exit(STATE_UNKNOWN);
761 case 'V': /* version */ 530 case 'V': /* version */
762 print_revision (progname, NP_VERSION); 531 print_revision(progname, NP_VERSION);
763 exit (STATE_UNKNOWN); 532 exit(STATE_UNKNOWN);
764 case 'v': /* verbose */ 533 case 'v': /* verbose */
765 verbose++; 534 verbose++;
766 break; 535 break;
767 536
768 /* Connection info */ 537 /* Connection info */
769 case 'C': /* group or community */ 538 case 'C': /* group or community */
770 community = optarg; 539 config.snmp_params.snmp_session.community = (unsigned char *)optarg;
540 config.snmp_params.snmp_session.community_len = strlen(optarg);
771 break; 541 break;
772 case 'H': /* Host or server */ 542 case 'H': /* Host or server */
773 server_address = optarg; 543 config.snmp_params.snmp_session.peername = optarg;
774 break; 544 break;
775 case 'p': /* TCP port number */ 545 case 'p': /*port number */
546 // Add port to "peername" below to not rely on argument order
776 port = optarg; 547 port = optarg;
777 break; 548 break;
778 case 'm': /* List of MIBS */ 549 case 'm': /* List of MIBS */
779 miblist = optarg; 550 miblist = optarg;
780 break; 551 break;
781 case 'n': /* usesnmpgetnext */ 552 case 'n': /* use_getnext instead of get */
782 usesnmpgetnext = true; 553 config.snmp_params.use_getnext = true;
783 break; 554 break;
784 case 'P': /* SNMP protocol version */ 555 case 'P': /* SNMP protocol version */
785 proto = optarg; 556 if (strcasecmp("1", optarg) == 0) {
557 config.snmp_params.snmp_session.version = SNMP_VERSION_1;
558 } else if (strcasecmp("2c", optarg) == 0) {
559 config.snmp_params.snmp_session.version = SNMP_VERSION_2c;
560 } else if (strcasecmp("3", optarg) == 0) {
561 config.snmp_params.snmp_session.version = SNMP_VERSION_3;
562 } else {
563 die(STATE_UNKNOWN, "invalid SNMP version/protocol: %s", optarg);
564 }
565 snmp_version_set_explicitely = true;
566
786 break; 567 break;
787 case 'N': /* SNMPv3 context */ 568 case 'N': /* SNMPv3 context name */
788 context = optarg; 569 config.snmp_params.snmp_session.contextName = optarg;
570 config.snmp_params.snmp_session.contextNameLen = strlen(optarg);
789 break; 571 break;
790 case 'L': /* security level */ 572 case 'L': /* security level */
791 seclevel = optarg; 573 if (strcasecmp("noAuthNoPriv", optarg) == 0) {
574 config.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_NOAUTH;
575 } else if (strcasecmp("authNoPriv", optarg) == 0) {
576 config.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
577 } else if (strcasecmp("authPriv", optarg) == 0) {
578 config.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
579 } else {
580 die(STATE_UNKNOWN, "invalid security level: %s", optarg);
581 }
792 break; 582 break;
793 case 'U': /* security username */ 583 case 'U': /* security username */
794 secname = optarg; 584 config.snmp_params.snmp_session.securityName = optarg;
585 config.snmp_params.snmp_session.securityNameLen = strlen(optarg);
795 break; 586 break;
796 case 'a': /* auth protocol */ 587 case 'a': /* auth protocol */
797 authproto = optarg; 588 // SNMPv3: SHA or MD5
589 // TODO Test for availability of individual protocols
590 if (strcasecmp("MD5", optarg) == 0) {
591 config.snmp_params.snmp_session.securityAuthProto = usmHMACMD5AuthProtocol;
592 config.snmp_params.snmp_session.securityAuthProtoLen =
593 OID_LENGTH(usmHMACMD5AuthProtocol);
594 } else if (strcasecmp("SHA", optarg) == 0) {
595 config.snmp_params.snmp_session.securityAuthProto = usmHMACSHA1AuthProtocol;
596 config.snmp_params.snmp_session.securityAuthProtoLen =
597 OID_LENGTH(usmHMACSHA1AuthProtocol);
598 } else if (strcasecmp("SHA224", optarg) == 0) {
599 config.snmp_params.snmp_session.securityAuthProto = usmHMAC128SHA224AuthProtocol;
600 config.snmp_params.snmp_session.securityAuthProtoLen =
601 OID_LENGTH(usmHMAC128SHA224AuthProtocol);
602 } else if (strcasecmp("SHA256", optarg) == 0) {
603 config.snmp_params.snmp_session.securityAuthProto = usmHMAC192SHA256AuthProtocol;
604 config.snmp_params.snmp_session.securityAuthProtoLen =
605 OID_LENGTH(usmHMAC192SHA256AuthProtocol);
606 } else if (strcasecmp("SHA384", optarg) == 0) {
607 config.snmp_params.snmp_session.securityAuthProto = usmHMAC256SHA384AuthProtocol;
608 config.snmp_params.snmp_session.securityAuthProtoLen =
609 OID_LENGTH(usmHMAC256SHA384AuthProtocol);
610 } else if (strcasecmp("SHA512", optarg) == 0) {
611 config.snmp_params.snmp_session.securityAuthProto = usmHMAC384SHA512AuthProtocol;
612 config.snmp_params.snmp_session.securityAuthProtoLen =
613 OID_LENGTH(usmHMAC384SHA512AuthProtocol);
614 } else {
615 die(STATE_UNKNOWN, "Unknown authentication protocol");
616 }
798 break; 617 break;
799 case 'x': /* priv protocol */ 618 case 'x': /* priv protocol */
800 privproto = optarg; 619 if (strcasecmp("DES", optarg) == 0) {
620#ifdef HAVE_USM_DES_PRIV_PROTOCOL
621 config.snmp_params.snmp_session.securityAuthProto = usmDESPrivProtocol;
622 config.snmp_params.snmp_session.securityAuthProtoLen =
623 OID_LENGTH(usmDESPrivProtocol);
624#else
625 die(STATE_UNKNOWN, "DES Privacy Protocol not available on this platform");
626#endif
627 } else if (strcasecmp("AES", optarg) == 0) {
628 config.snmp_params.snmp_session.securityAuthProto = usmAESPrivProtocol;
629 config.snmp_params.snmp_session.securityAuthProtoLen =
630 OID_LENGTH(usmAESPrivProtocol);
631 // } else if (strcasecmp("AES128", optarg)) {
632 // config.snmp_session.securityAuthProto = usmAES128PrivProtocol;
633 // config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmAES128PrivProtocol)
634 // / OID_LENGTH(oid);
635 } else if (strcasecmp("AES192", optarg) == 0) {
636 config.snmp_params.snmp_session.securityAuthProto = usmAES192PrivProtocol;
637 config.snmp_params.snmp_session.securityAuthProtoLen =
638 OID_LENGTH(usmAES192PrivProtocol);
639 } else if (strcasecmp("AES256", optarg) == 0) {
640 config.snmp_params.snmp_session.securityAuthProto = usmAES256PrivProtocol;
641 config.snmp_params.snmp_session.securityAuthProtoLen =
642 OID_LENGTH(usmAES256PrivProtocol);
643 // } else if (strcasecmp("AES192Cisco", optarg)) {
644 // config.snmp_session.securityAuthProto = usmAES192CiscoPrivProtocol;
645 // config.snmp_session.securityAuthProtoLen =
646 // sizeof(usmAES192CiscoPrivProtocol) / sizeof(oid); } else if
647 // (strcasecmp("AES256Cisco", optarg)) { config.snmp_session.securityAuthProto =
648 // usmAES256CiscoPrivProtocol; config.snmp_session.securityAuthProtoLen =
649 // sizeof(usmAES256CiscoPrivProtocol) / sizeof(oid); } else if
650 // (strcasecmp("AES192Cisco2", optarg)) { config.snmp_session.securityAuthProto
651 // = usmAES192Cisco2PrivProtocol; config.snmp_session.securityAuthProtoLen =
652 // sizeof(usmAES192Cisco2PrivProtocol) / sizeof(oid); } else if
653 // (strcasecmp("AES256Cisco2", optarg)) { config.snmp_session.securityAuthProto
654 // = usmAES256Cisco2PrivProtocol; config.snmp_session.securityAuthProtoLen =
655 // sizeof(usmAES256Cisco2PrivProtocol) / sizeof(oid);
656 } else {
657 die(STATE_UNKNOWN, "Unknown privacy protocol");
658 }
801 break; 659 break;
802 case 'A': /* auth passwd */ 660 case 'A': /* auth passwd */
803 authpasswd = optarg; 661 authpasswd = (unsigned char *)optarg;
804 break; 662 break;
805 case 'X': /* priv passwd */ 663 case 'X': /* priv passwd */
806 privpasswd = optarg; 664 privpasswd = (unsigned char *)optarg;
807 break; 665 break;
808 case 't': /* timeout period */ 666 case 'e':
809 if (!is_integer (optarg)) 667 case 'E':
810 usage2 (_("Timeout interval must be a positive integer"), optarg); 668 if (!is_integer(optarg)) {
811 else 669 usage2(_("Retries interval must be a positive integer"), optarg);
812 timeout_interval = atoi (optarg); 670 } else {
671 config.snmp_params.snmp_session.retries = atoi(optarg);
672 }
813 break; 673 break;
814 674 case 't': /* timeout period */
815 /* Test parameters */ 675 if (!is_integer(optarg)) {
816 case 'c': /* critical threshold */ 676 usage2(_("Timeout interval must be a positive integer"), optarg);
817 critical_thresholds = optarg; 677 } else {
678 timeout_interval = (unsigned int)atoi(optarg);
679 }
818 break; 680 break;
819 case 'w': /* warning threshold */ 681
820 warning_thresholds = optarg; 682 /* Test parameters */
683 case 'c': /* critical threshold */
684 check_snmp_set_thresholds(optarg, config.snmp_params.test_units, oid_counter, true);
821 break; 685 break;
822 case 'e': /* PRELIMINARY - may change */ 686 case 'w': /* warning threshold */
823 case 'E': /* PRELIMINARY - may change */ 687 check_snmp_set_thresholds(optarg, config.snmp_params.test_units, oid_counter, false);
824 if (!is_integer (optarg))
825 usage2 (_("Retries interval must be a positive integer"), optarg);
826 else
827 retries = atoi(optarg);
828 break; 688 break;
829 case 'o': /* object identifier */ 689 case 'o': /* object identifier */
830 if ( strspn( optarg, "0123456789.," ) != strlen( optarg ) ) { 690 if (strspn(optarg, "0123456789.,") != strlen(optarg)) {
831 /* 691 /*
832 * we have something other than digits, periods and comas, 692 * we have something other than digits, periods and comas,
833 * so we have a mib variable, rather than just an SNMP OID, 693 * so we have a mib variable, rather than just an SNMP OID,
834 * so we have to actually read the mib files 694 * so we have to actually read the mib files
835 */ 695 */
836 needmibs = true; 696 config.snmp_params.need_mibs = true;
837 }
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));
842 }
843 oids[j] = strdup(ptr);
844 } 697 }
845 numoids = j; 698
846 if (c == 'E' || c == 'e') { 699 for (char *ptr = strtok(optarg, ", "); ptr != NULL;
847 jj++; 700 ptr = strtok(NULL, ", "), tmp_oid_counter++) {
848 while (j+1 >= eval_size) { 701 config.snmp_params.test_units[tmp_oid_counter].oid = strdup(ptr);
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);
852 }
853 if (c == 'E')
854 eval_method[j+1] |= WARN_PRESENT;
855 else if (c == 'e')
856 eval_method[j+1] |= CRIT_PRESENT;
857 } 702 }
858 break; 703 break;
859 case 'z': /* Null OID Return Check */ 704 case 'z': /* Null OID Return Check */
860 if (!is_integer (optarg)) 705 if (!is_integer(optarg)) {
861 usage2 (_("Exit status must be a positive integer"), optarg); 706 usage2(_("Exit status must be a positive integer"), optarg);
862 else 707 } else {
863 nulloid = atoi(optarg); 708 config.evaluation_params.nulloid_result = atoi(optarg);
864 break;
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);
872 } 709 }
873 eval_method[jj++] = CRIT_STRING;
874 break; 710 break;
875 case 'R': /* regex */ 711 case 's': /* string or substring */
712 strncpy(config.evaluation_params.string_cmp_value, optarg,
713 sizeof(config.evaluation_params.string_cmp_value) - 1);
714 config.evaluation_params
715 .string_cmp_value[sizeof(config.evaluation_params.string_cmp_value) - 1] = 0;
716 config.snmp_params.test_units[eval_counter++].eval_mthd.crit_string = true;
717 break;
718 case 'R': /* regex */
876 cflags = REG_ICASE; 719 cflags = REG_ICASE;
877 // fall through 720 // fall through
878 case 'r': /* regex */ 721 case 'r': /* regex */
722 {
723 char regex_expect[MAX_INPUT_BUFFER] = "";
879 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 724 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
880 strncpy (regex_expect, optarg, sizeof (regex_expect) - 1); 725 strncpy(regex_expect, optarg, sizeof(regex_expect) - 1);
881 regex_expect[sizeof (regex_expect) - 1] = 0; 726 regex_expect[sizeof(regex_expect) - 1] = 0;
882 errcode = regcomp (&preg, regex_expect, cflags); 727 int errcode = regcomp(&config.evaluation_params.regex_cmp_value, regex_expect, cflags);
883 if (errcode != 0) { 728 if (errcode != 0) {
884 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 729 char errbuf[MAX_INPUT_BUFFER] = "";
885 printf (_("Could Not Compile Regular Expression")); 730 regerror(errcode, &config.evaluation_params.regex_cmp_value, errbuf,
886 return ERROR; 731 MAX_INPUT_BUFFER);
732 printf("Could Not Compile Regular Expression: %s", errbuf);
733 process_arguments_wrapper result = {
734 .errorcode = ERROR,
735 };
736 return result;
887 } 737 }
888 while (jj >= eval_size) { 738 config.snmp_params.test_units[eval_counter++].eval_mthd.crit_regex = true;
889 eval_size += OID_COUNT_STEP; 739 } break;
890 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); 740 case 'l': /* label */
891 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8); 741 {
742 if (labels_counter >= config.snmp_params.num_of_test_units) {
743 break;
892 } 744 }
893 eval_method[jj++] = CRIT_REGEX; 745 char *ptr = trim_whitespaces_and_check_quoting(optarg);
894 break; 746 if (ptr[0] == '\'') {
895 747 config.snmp_params.test_units[labels_counter].label = ptr + 1;
896 /* Format */ 748 } else {
897 case 'd': /* delimiter */ 749 config.snmp_params.test_units[labels_counter].label = ptr;
898 delimiter = strscpy (delimiter, optarg);
899 break;
900 case 'D': /* output-delimiter */
901 output_delim = strscpy (output_delim, optarg);
902 break;
903 case 'l': /* label */
904 nlabels++;
905 if (nlabels > labels_size) {
906 labels_size += 8;
907 labels = realloc (labels, labels_size * sizeof(*labels));
908 if (labels == NULL)
909 die (STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels);
910 } 750 }
911 labels[nlabels - 1] = optarg; 751
912 ptr = thisarg (optarg); 752 while (ptr && (ptr = get_next_argument(ptr))) {
913 labels[nlabels - 1] = ptr; 753 labels_counter++;
914 if (ptr[0] == '\'') 754 ptr = trim_whitespaces_and_check_quoting(ptr);
915 labels[nlabels - 1] = ptr + 1; 755 if (ptr[0] == '\'') {
916 while (ptr && (ptr = nextarg (ptr))) { 756 config.snmp_params.test_units[labels_counter].label = ptr + 1;
917 nlabels++; 757 } else {
918 if (nlabels > labels_size) { 758 config.snmp_params.test_units[labels_counter].label = ptr;
919 labels_size += 8;
920 labels = realloc (labels, labels_size * sizeof(*labels));
921 if (labels == NULL)
922 die (STATE_UNKNOWN, _("Could not reallocate labels\n"));
923 } 759 }
924 ptr = thisarg (ptr);
925 if (ptr[0] == '\'')
926 labels[nlabels - 1] = ptr + 1;
927 else
928 labels[nlabels - 1] = ptr;
929 } 760 }
930 break; 761 labels_counter++;
931 case 'u': /* units */ 762 } break;
932 units = optarg; 763 case 'u': /* units */
933 nunits++; 764 {
934 if (nunits > unitv_size) { 765 if (unitv_counter >= config.snmp_params.num_of_test_units) {
935 unitv_size += 8; 766 break;
936 unitv = realloc (unitv, unitv_size * sizeof(*unitv)); 767 }
937 if (unitv == NULL) 768 char *ptr = trim_whitespaces_and_check_quoting(optarg);
938 die (STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits); 769 if (ptr[0] == '\'') {
770 config.snmp_params.test_units[unitv_counter].unit_value = ptr + 1;
771 } else {
772 config.snmp_params.test_units[unitv_counter].unit_value = ptr;
939 } 773 }
940 unitv[nunits - 1] = optarg; 774 while (ptr && (ptr = get_next_argument(ptr))) {
941 ptr = thisarg (optarg); 775 unitv_counter++;
942 unitv[nunits - 1] = ptr; 776 ptr = trim_whitespaces_and_check_quoting(ptr);
943 if (ptr[0] == '\'') 777 if (ptr[0] == '\'') {
944 unitv[nunits - 1] = ptr + 1; 778 config.snmp_params.test_units[unitv_counter].unit_value = ptr + 1;
945 while (ptr && (ptr = nextarg (ptr))) { 779 } else {
946 if (nunits > unitv_size) { 780 config.snmp_params.test_units[unitv_counter].unit_value = ptr;
947 unitv_size += 8;
948 unitv = realloc (unitv, unitv_size * sizeof(*unitv));
949 if (units == NULL)
950 die (STATE_UNKNOWN, _("Could not realloc() units\n"));
951 } 781 }
952 nunits++;
953 ptr = thisarg (ptr);
954 if (ptr[0] == '\'')
955 unitv[nunits - 1] = ptr + 1;
956 else
957 unitv[nunits - 1] = ptr;
958 } 782 }
783 unitv_counter++;
784 } break;
785 case offset_index:
786 config.evaluation_params.offset = strtod(optarg, NULL);
787 config.evaluation_params.offset_set = true;
959 break; 788 break;
960 case L_CALCULATE_RATE: 789 case invert_search_index:
961 if(calculate_rate==0) 790 config.evaluation_params.invert_search = false;
962 np_enable_state(NULL, 1);
963 calculate_rate = 1;
964 break;
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);
968 break;
969 case L_OFFSET:
970 offset=strtod(optarg,NULL);
971 break;
972 case L_INVERT_SEARCH:
973 invert_search=1;
974 break; 791 break;
975 case 'O': 792 case 'O':
976 perf_labels=0; 793 config.evaluation_params.use_oid_as_perf_data_label = true;
977 break; 794 break;
978 case '4': 795 case '4':
796 // The default, do something here to be exclusive to -6 instead of doing nothing?
797 connection_prefix = "udp";
979 break; 798 break;
980 case '6': 799 case '6':
981 xasprintf(&ip_version, "udp6:"); 800 connection_prefix = "udp6";
982 if(verbose>2) 801 break;
983 printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n"); 802 case connection_prefix_index:
803 connection_prefix = optarg;
984 break; 804 break;
985 case 'M': 805 case 'M':
986 if ( strspn( optarg, "0123456789.," ) == strlen( optarg ) ) { 806 if (strspn(optarg, "0123456789.,") == strlen(optarg)) {
987 multiplier=strtod(optarg,NULL); 807 config.evaluation_params.multiplier = strtod(optarg, NULL);
808 config.evaluation_params.multiplier_set = true;
988 } 809 }
989 break; 810 break;
990 case 'f': 811 case ignore_mib_parsing_errors_index:
991 if (multiplier != 1.0) { 812 config.snmp_params.ignore_mib_parsing_errors = true;
992 fmtstr=optarg; 813 break;
993 fmtstr_set = true; 814 case 'f': // Deprecated format option for floating point values
815 break;
816 case output_format_index: {
817 parsed_output_format parser = mp_parse_output_format(optarg);
818 if (!parser.parsing_success) {
819 // TODO List all available formats here, maybe add anothoer usage function
820 printf("Invalid output format: %s\n", optarg);
821 exit(STATE_UNKNOWN);
822 }
823
824 config.output_format_is_set = true;
825 config.output_format = parser.output_format;
826 break;
827 }
828 case calculate_rate:
829 config.evaluation_params.calculate_rate = true;
830 break;
831 case rate_multiplier:
832 if (!is_integer(optarg) ||
833 ((config.evaluation_params.rate_multiplier = (unsigned int)atoi(optarg)) <= 0)) {
834 usage2(_("Rate multiplier must be a positive integer"), optarg);
994 } 835 }
995 break; 836 break;
996 case L_IGNORE_MIB_PARSING_ERRORS: 837 default:
997 ignore_mib_parsing_errors = true; 838 die(STATE_UNKNOWN, "Unknown option");
998 } 839 }
999 } 840 }
1000 841
1001 if (server_address == NULL) 842 if (config.snmp_params.snmp_session.peername == NULL) {
1002 server_address = argv[optind]; 843 config.snmp_params.snmp_session.peername = argv[optind];
1003 844 }
1004 if (community == NULL)
1005 community = strdup (DEFAULT_COMMUNITY);
1006
1007 return validate_arguments ();
1008}
1009
1010
1011/******************************************************************************
1012
1013@@-
1014<sect3>
1015<title>validate_arguments</title>
1016
1017<para>&PROTO_validate_arguments;</para>
1018
1019<para>Checks to see if the default miblist needs to be loaded. Also verifies
1020the authentication and authorization combinations based on protocol version
1021selected.</para>
1022
1023<para></para>
1024
1025</sect3>
1026-@@
1027******************************************************************************/
1028
1029
1030 845
1031static int 846 // Build true peername here if necessary
1032validate_arguments () 847 if (connection_prefix != NULL) {
1033{ 848 // We got something in the connection prefix
1034 /* check whether to load locally installed MIBS (CPU/disk intensive) */ 849 if (strcasecmp(connection_prefix, "udp") == 0) {
1035 if (miblist == NULL) { 850 // The default, do nothing
1036 if (needmibs) { 851 } else if (strcasecmp(connection_prefix, "tcp") == 0) {
1037 miblist = strdup (DEFAULT_MIBLIST); 852 // use tcp/ipv4
1038 }else{ 853 xasprintf(&config.snmp_params.snmp_session.peername, "tcp:%s",
1039 miblist = ""; /* don't read any mib files for numeric oids */ 854 config.snmp_params.snmp_session.peername);
855 } else if (strcasecmp(connection_prefix, "tcp6") == 0 ||
856 strcasecmp(connection_prefix, "tcpv6") == 0 ||
857 strcasecmp(connection_prefix, "tcpipv6") == 0 ||
858 strcasecmp(connection_prefix, "udp6") == 0 ||
859 strcasecmp(connection_prefix, "udpipv6") == 0 ||
860 strcasecmp(connection_prefix, "udpv6") == 0) {
861 // Man page (or net-snmp) code says IPv6 addresses should be wrapped in [], but it
862 // works anyway therefore do nothing here
863 xasprintf(&config.snmp_params.snmp_session.peername, "%s:%s", connection_prefix,
864 config.snmp_params.snmp_session.peername);
865 } else if (strcmp(connection_prefix, "tls") == 0) {
866 // TODO: Anything else to do here?
867 xasprintf(&config.snmp_params.snmp_session.peername, "tls:%s",
868 config.snmp_params.snmp_session.peername);
869 } else if (strcmp(connection_prefix, "dtls") == 0) {
870 // TODO: Anything else to do here?
871 xasprintf(&config.snmp_params.snmp_session.peername, "dtls:%s",
872 config.snmp_params.snmp_session.peername);
873 } else if (strcmp(connection_prefix, "unix") == 0) {
874 // TODO: Check whether this is a valid path?
875 xasprintf(&config.snmp_params.snmp_session.peername, "unix:%s",
876 config.snmp_params.snmp_session.peername);
877 } else if (strcmp(connection_prefix, "ipx") == 0) {
878 xasprintf(&config.snmp_params.snmp_session.peername, "ipx:%s",
879 config.snmp_params.snmp_session.peername);
880 } else {
881 // Don't know that prefix, die here
882 die(STATE_UNKNOWN, "Unknown connection prefix");
1040 } 883 }
1041 } 884 }
1042 885
1043 /* Check server_address is given */ 886 /* Check server_address is given */
1044 if (server_address == NULL) 887 if (config.snmp_params.snmp_session.peername == NULL) {
1045 die(STATE_UNKNOWN, _("No host specified\n")); 888 die(STATE_UNKNOWN, _("No host specified\n"));
889 }
1046 890
1047 /* Check oid is given */ 891 if (port != NULL) {
1048 if (numoids == 0) 892 xasprintf(&config.snmp_params.snmp_session.peername, "%s:%s",
1049 die(STATE_UNKNOWN, _("No OIDs specified\n")); 893 config.snmp_params.snmp_session.peername, port);
1050
1051 if (proto == NULL)
1052 xasprintf(&proto, DEFAULT_PROTOCOL);
1053
1054 if ((strcmp(proto,"1") == 0) || (strcmp(proto, "2c")==0)) { /* snmpv1 or snmpv2c */
1055 numauthpriv = 2;
1056 authpriv = calloc (numauthpriv, sizeof (char *));
1057 authpriv[0] = strdup ("-c");
1058 authpriv[1] = strdup (community);
1059 } 894 }
1060 else if ( strcmp (proto, "3") == 0 ) { /* snmpv3 args */ 895
1061 if (!(context == NULL)) { 896 /* check whether to load locally installed MIBS (CPU/disk intensive) */
1062 numcontext = 2; 897 if (miblist == NULL) {
1063 contextargs = calloc (numcontext, sizeof (char *)); 898 if (config.snmp_params.need_mibs) {
1064 contextargs[0] = strdup ("-n"); 899 setenv("MIBLS", DEFAULT_MIBLIST, 1);
1065 contextargs[1] = strdup (context); 900 } else {
901 setenv("MIBLS", "NONE", 1);
902 miblist = ""; /* don't read any mib files for numeric oids */
1066 } 903 }
904 } else {
905 // Blatantly stolen from snmplib/snmp_parse_args
906 setenv("MIBS", miblist, 1);
907 }
1067 908
1068 if (seclevel == NULL) 909 // Historical default is SNMP v2c
1069 xasprintf(&seclevel, "noAuthNoPriv"); 910 if (!snmp_version_set_explicitely && config.snmp_params.snmp_session.community != NULL) {
911 config.snmp_params.snmp_session.version = SNMP_VERSION_2c;
912 }
1070 913
1071 if (secname == NULL) 914 if ((config.snmp_params.snmp_session.version == SNMP_VERSION_1) ||
915 (config.snmp_params.snmp_session.version == SNMP_VERSION_2c)) { /* snmpv1 or snmpv2c */
916 /*
917 config.numauthpriv = 2;
918 config.authpriv = calloc(config.numauthpriv, sizeof(char *));
919 config.authpriv[0] = strdup("-c");
920 config.authpriv[1] = strdup(community);
921 */
922 } else if (config.snmp_params.snmp_session.version == SNMP_VERSION_3) { /* snmpv3 args */
923 // generate keys for priv and auth here (if demanded)
924
925 if (config.snmp_params.snmp_session.securityName == NULL) {
1072 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname"); 926 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname");
927 }
1073 928
1074 if (strcmp(seclevel, "noAuthNoPriv") == 0) { 929 switch (config.snmp_params.snmp_session.securityLevel) {
1075 numauthpriv = 4; 930 case SNMP_SEC_LEVEL_AUTHPRIV: {
1076 authpriv = calloc (numauthpriv, sizeof (char *)); 931 if (authpasswd == NULL) {
1077 authpriv[0] = strdup ("-l"); 932 die(STATE_UNKNOWN,
1078 authpriv[1] = strdup ("noAuthNoPriv"); 933 "No authentication passphrase was given, but authorization was requested");
1079 authpriv[2] = strdup ("-u");
1080 authpriv[3] = strdup (secname);
1081 } else {
1082 if (! ( (strcmp(seclevel, "authNoPriv")==0) || (strcmp(seclevel, "authPriv")==0) ) ) {
1083 usage2 (_("Invalid seclevel"), seclevel);
1084 } 934 }
1085 935 // auth and priv
1086 if (authproto == NULL ) 936 int priv_key_generated = generate_Ku(
1087 xasprintf(&authproto, DEFAULT_AUTH_PROTOCOL); 937 config.snmp_params.snmp_session.securityPrivProto,
1088 938 (unsigned int)config.snmp_params.snmp_session.securityPrivProtoLen, authpasswd,
1089 if (authpasswd == NULL) 939 strlen((const char *)authpasswd), config.snmp_params.snmp_session.securityPrivKey,
1090 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd"); 940 &config.snmp_params.snmp_session.securityPrivKeyLen);
1091 941
1092 if ( strcmp(seclevel, "authNoPriv") == 0 ) { 942 if (priv_key_generated != SNMPERR_SUCCESS) {
1093 numauthpriv = 8; 943 die(STATE_UNKNOWN, "Failed to generate privacy key");
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);
1106
1107 if (privpasswd == NULL)
1108 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd");
1109
1110 numauthpriv = 12;
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);
1124 } 944 }
1125 } 945 }
1126 946 // fall through
1127 } 947 case SNMP_SEC_LEVEL_AUTHNOPRIV: {
1128 else { 948 if (privpasswd == NULL) {
1129 usage2 (_("Invalid SNMP version"), proto); 949 die(STATE_UNKNOWN, "No privacy passphrase was given, but privacy was requested");
950 }
951 int auth_key_generated = generate_Ku(
952 config.snmp_params.snmp_session.securityAuthProto,
953 (unsigned int)config.snmp_params.snmp_session.securityAuthProtoLen, privpasswd,
954 strlen((const char *)privpasswd), config.snmp_params.snmp_session.securityAuthKey,
955 &config.snmp_params.snmp_session.securityAuthKeyLen);
956
957 if (auth_key_generated != SNMPERR_SUCCESS) {
958 die(STATE_UNKNOWN, "Failed to generate privacy key");
959 }
960 } break;
961 case SNMP_SEC_LEVEL_NOAUTH:
962 // No auth, no priv, not much todo
963 break;
964 }
1130 } 965 }
1131 966
1132 return OK; 967 process_arguments_wrapper result = {
968 .config = config,
969 .errorcode = OK,
970 };
971 return result;
1133} 972}
1134 973
1135
1136
1137/* trim leading whitespace 974/* trim leading whitespace
1138 if there is a leading quote, make sure it balances */ 975 if there is a leading quote, make sure it balances */
1139 976char *trim_whitespaces_and_check_quoting(char *str) {
1140static char * 977 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
1141thisarg (char *str) 978 if (str[0] == '\'') { /* handle SIMPLE quoted strings */
1142{ 979 if (strlen(str) == 1 || !strstr(str + 1, "'")) {
1143 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 980 die(STATE_UNKNOWN, _("Unbalanced quotes\n"));
1144 if (str[0] == '\'') { /* handle SIMPLE quoted strings */ 981 }
1145 if (strlen (str) == 1 || !strstr (str + 1, "'"))
1146 die (STATE_UNKNOWN, _("Unbalanced quotes\n"));
1147 } 982 }
1148 return str; 983 return str;
1149} 984}
1150 985
1151
1152
1153/* if there's a leading quote, advance to the trailing quote 986/* if there's a leading quote, advance to the trailing quote
1154 set the trailing quote to '\x0' 987 set the trailing quote to '\x0'
1155 if the string continues, advance beyond the comma */ 988 if the string continues, advance beyond the comma */
1156 989
1157static char * 990char *get_next_argument(char *str) {
1158nextarg (char *str)
1159{
1160 if (str[0] == '\'') { 991 if (str[0] == '\'') {
1161 str[0] = 0; 992 str[0] = 0;
1162 if (strlen (str) > 1) { 993 if (strlen(str) > 1) {
1163 str = strstr (str + 1, "'"); 994 str = strstr(str + 1, "'");
1164 return (++str); 995 return (++str);
1165 } 996 }
1166 else { 997 return NULL;
1167 return NULL;
1168 }
1169 } 998 }
1170 if (str[0] == ',') { 999 if (str[0] == ',') {
1171 str[0] = 0; 1000 str[0] = 0;
1172 if (strlen (str) > 1) { 1001 if (strlen(str) > 1) {
1173 return (++str); 1002 return (++str);
1174 } 1003 }
1175 else { 1004 return NULL;
1176 return NULL;
1177 }
1178 } 1005 }
1179 if ((str = strstr (str, ",")) && strlen (str) > 1) { 1006 if ((str = strstr(str, ",")) && strlen(str) > 1) {
1180 str[0] = 0; 1007 str[0] = 0;
1181 return (++str); 1008 return (++str);
1182 } 1009 }
1183 return NULL; 1010 return NULL;
1184} 1011}
1185 1012
1013void print_help(void) {
1014 print_revision(progname, NP_VERSION);
1186 1015
1016 printf(COPYRIGHT, copyright, email);
1187 1017
1188/* multiply result (values 0 < n < 1 work as divider) */ 1018 printf("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
1189static char *
1190multiply (char *str)
1191{
1192 char *endptr;
1193 double val;
1194 char *conv = "%f";
1195
1196 if(multiplier == 1)
1197 return(str);
1198
1199 if(verbose>2)
1200 printf(" multiply input: %s\n", str);
1201
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);
1205 }
1206
1207 if(verbose>2)
1208 printf(" multiply extracted double: %f\n", val);
1209 val *= multiplier;
1210 if (fmtstr_set) {
1211 conv = fmtstr;
1212 }
1213 if (val == (int)val) {
1214 snprintf(buffer, DEFAULT_BUFFER_SIZE, "%.0f", val);
1215 } else {
1216 if(verbose>2)
1217 printf(" multiply using format: %s\n", conv);
1218 snprintf(buffer, DEFAULT_BUFFER_SIZE, conv, val);
1219 }
1220 if(verbose>2)
1221 printf(" multiply result: %s\n", buffer);
1222 return buffer;
1223}
1224
1225
1226static void
1227print_help (void)
1228{
1229 print_revision (progname, NP_VERSION);
1230
1231 printf (COPYRIGHT, copyright, email);
1232
1233 printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
1234 1019
1235 printf ("\n\n"); 1020 printf("\n\n");
1236 1021
1237 print_usage (); 1022 print_usage();
1238 1023
1239 printf (UT_HELP_VRSN); 1024 printf(UT_HELP_VRSN);
1240 printf (UT_EXTRA_OPTS); 1025 printf(UT_EXTRA_OPTS);
1241 printf (UT_IPv46); 1026 printf(UT_HOST_PORT, 'p', DEFAULT_PORT);
1242
1243 printf (UT_HOST_PORT, 'p', DEFAULT_PORT);
1244 1027
1245 /* SNMP and Authentication Protocol */ 1028 /* SNMP and Authentication Protocol */
1246 printf (" %s\n", "-n, --next"); 1029 printf(" %s\n", "-n, --next");
1247 printf (" %s\n", _("Use SNMP GETNEXT instead of SNMP GET")); 1030 printf(" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
1248 printf (" %s\n", "-P, --protocol=[1|2c|3]"); 1031 printf(" %s\n", "-P, --protocol=[1|2c|3]");
1249 printf (" %s\n", _("SNMP protocol version")); 1032 printf(" %s\n", _("SNMP protocol version"));
1250 printf (" %s\n", "-N, --context=CONTEXT"); 1033 printf(" %s\n", "-N, --context=CONTEXT");
1251 printf (" %s\n", _("SNMPv3 context")); 1034 printf(" %s\n", _("SNMPv3 context"));
1252 printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]"); 1035 printf(" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
1253 printf (" %s\n", _("SNMPv3 securityLevel")); 1036 printf(" %s\n", _("SNMPv3 securityLevel"));
1254 printf (" %s\n", "-a, --authproto=AUTHENTICATION_PROTOCOL"); 1037 printf(" %s\n", "-a, --authproto=[MD5|SHA]");
1255 printf (" %s\n", _("SNMPv3 authentication protocol (default MD5), available options depend on the specific version of the net-snmp tools")); 1038 printf(" %s\n", _("SNMPv3 auth proto"));
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")); 1039#ifdef HAVE_USM_DES_PRIV_PROTOCOL
1257 printf (" %s\n", "-x, --privproto=PRIVACY_PROTOCOL"); 1040 printf(" %s\n", "-x, --privproto=[DES|AES]");
1258 printf (" %s\n", _("SNMPv3 privacy protocol (default DES), available options depend on the specific version of the net-snmp tools")); 1041 printf(" %s\n", _("SNMPv3 priv proto (default DES)"));
1259 printf (" %s\n", _("if < 5.8 DES and AES should be available, if >= 5.8 additionally AES-192 and AES-256")); 1042#else
1043 printf(" %s\n", "-x, --privproto=[AES]");
1044 printf(" %s\n", _("SNMPv3 priv proto (default AES)"));
1045#endif
1260 1046
1261 /* Authentication Tokens*/ 1047 /* Authentication Tokens*/
1262 printf (" %s\n", "-C, --community=STRING"); 1048 printf(" %s\n", "-C, --community=STRING");
1263 printf (" %s ", _("Optional community string for SNMP communication")); 1049 printf(" %s ", _("Optional community string for SNMP communication"));
1264 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY); 1050 printf("(%s \"%s\")\n", _("default is"), DEFAULT_COMMUNITY);
1265 printf (" %s\n", "-U, --secname=USERNAME"); 1051 printf(" %s\n", "-U, --secname=USERNAME");
1266 printf (" %s\n", _("SNMPv3 username")); 1052 printf(" %s\n", _("SNMPv3 username"));
1267 printf (" %s\n", "-A, --authpasswd=PASSWORD"); 1053 printf(" %s\n", "-A, --authpasswd=PASSWORD");
1268 printf (" %s\n", _("SNMPv3 authentication password")); 1054 printf(" %s\n", _("SNMPv3 authentication password"));
1269 printf (" %s\n", "-X, --privpasswd=PASSWORD"); 1055 printf(" %s\n", "-X, --privpasswd=PASSWORD");
1270 printf (" %s\n", _("SNMPv3 privacy password")); 1056 printf(" %s\n", _("SNMPv3 privacy password"));
1057 printf(" %s\n", "--connection-prefix");
1058 printf(" Connection prefix, may be one of udp, udp6, tcp, unix, ipx, udp6, udpv6, udpipv6, "
1059 "tcp6, tcpv6, tcpipv6, tls, dtls - "
1060 "default is \"udp\"\n");
1271 1061
1272 /* OID Stuff */ 1062 /* OID Stuff */
1273 printf (" %s\n", "-o, --oid=OID(s)"); 1063 printf(" %s\n", "-o, --oid=OID(s)");
1274 printf (" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query")); 1064 printf(" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
1275 printf (" %s\n", "-m, --miblist=STRING"); 1065 printf(" %s\n", "-m, --miblist=STRING");
1276 printf (" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'")); 1066 printf(" %s\n",
1277 printf (" %s\n", _("for symbolic OIDs.)")); 1067 _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
1278 printf (" %s\n", "-d, --delimiter=STRING"); 1068 printf(" %s\n", _("for symbolic OIDs.)"));
1279 printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER); 1069 printf(" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1280 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered")); 1070 printf(" %s\n", _("to be the data that should be used in the evaluation."));
1281 printf (" %s\n", _("to be the data that should be used in the evaluation.")); 1071 printf(" %s\n", "-z, --nulloid=#");
1282 printf (" %s\n", "-z, --nulloid=#"); 1072 printf(" %s\n", _("If the check returns a 0 length string or NULL value"));
1283 printf (" %s\n", _("If the check returns a 0 length string or NULL value")); 1073 printf(" %s\n", _("This option allows you to choose what status you want it to exit"));
1284 printf (" %s\n", _("This option allows you to choose what status you want it to exit")); 1074 printf(" %s\n", _("Excluding this option renders the default exit of 3(STATE_UNKNOWN)"));
1285 printf (" %s\n", _("Excluding this option renders the default exit of 3(STATE_UNKNOWN)")); 1075 printf(" %s\n", _("0 = OK"));
1286 printf (" %s\n", _("0 = OK")); 1076 printf(" %s\n", _("1 = WARNING"));
1287 printf (" %s\n", _("1 = WARNING")); 1077 printf(" %s\n", _("2 = CRITICAL"));
1288 printf (" %s\n", _("2 = CRITICAL")); 1078 printf(" %s\n", _("3 = UNKNOWN"));
1289 printf (" %s\n", _("3 = UNKNOWN"));
1290 1079
1291 /* Tests Against Integers */ 1080 /* Tests Against Integers */
1292 printf (" %s\n", "-w, --warning=THRESHOLD(s)"); 1081 printf(" %s\n", "-w, --warning=THRESHOLD(s)");
1293 printf (" %s\n", _("Warning threshold range(s)")); 1082 printf(" %s\n", _("Warning threshold range(s)"));
1294 printf (" %s\n", "-c, --critical=THRESHOLD(s)"); 1083 printf(" %s\n", "-c, --critical=THRESHOLD(s)");
1295 printf (" %s\n", _("Critical threshold range(s)")); 1084 printf(" %s\n", _("Critical threshold range(s)"));
1296 printf (" %s\n", "--rate"); 1085 printf(" %s\n", "--offset=OFFSET");
1297 printf (" %s\n", _("Enable rate calculation. See 'Rate Calculation' below")); 1086 printf(" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data"));
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"));
1302 1087
1303 /* Tests Against Strings */ 1088 /* Tests Against Strings */
1304 printf (" %s\n", "-s, --string=STRING"); 1089 printf(" %s\n", "-s, --string=STRING");
1305 printf (" %s\n", _("Return OK state (for that OID) if STRING is an exact match")); 1090 printf(" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
1306 printf (" %s\n", "-r, --ereg=REGEX"); 1091 printf(" %s\n", "-r, --ereg=REGEX");
1307 printf (" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches")); 1092 printf(" %s\n",
1308 printf (" %s\n", "-R, --eregi=REGEX"); 1093 _("Return OK state (for that OID) if extended regular expression REGEX matches"));
1309 printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches")); 1094 printf(" %s\n", "-R, --eregi=REGEX");
1310 printf (" %s\n", "--invert-search"); 1095 printf(" %s\n",
1311 printf (" %s\n", _("Invert search result (CRITICAL if found)")); 1096 _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
1097 printf(" %s\n", "--invert-search");
1098 printf(" %s\n", _("Invert search result (CRITICAL if found)"));
1312 1099
1313 /* Output Formatting */ 1100 /* Output Formatting */
1314 printf (" %s\n", "-l, --label=STRING"); 1101 printf(" %s\n", "-l, --label=STRING");
1315 printf (" %s\n", _("Prefix label for output from plugin")); 1102 printf(" %s\n", _("Prefix label for output from plugin"));
1316 printf (" %s\n", "-u, --units=STRING"); 1103 printf(" %s\n", "-u, --units=STRING");
1317 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.').")); 1104 printf(" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1318 printf (" %s\n", "-D, --output-delimiter=STRING"); 1105 printf(" %s\n", "-M, --multiplier=FLOAT");
1319 printf (" %s\n", _("Separates output on multiple OID requests")); 1106 printf(" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1"));
1320 printf (" %s\n", "-M, --multiplier=FLOAT"); 1107 printf(UT_OUTPUT_FORMAT);
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)"));
1324
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);
1329
1330 printf (" %s\n", "-O, --perf-oids");
1331 printf (" %s\n", _("Label performance data with OIDs instead of --label's"));
1332
1333 printf (" %s\n", "--ignore-mib-parsing-errors");
1334 printf (" %s\n", _("Tell snmpget to not print errors encountered when parsing MIB files"));
1335
1336 printf (UT_VERBOSE);
1337
1338 printf ("\n");
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."));
1342
1343 printf ("\n");
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)."));
1347 1108
1348 printf(" -%s", UT_THRESHOLDS_NOTES); 1109 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1110 printf(" %s\n", _("NOTE the final timeout value is calculated using this formula: "
1111 "timeout_interval * retries + 5"));
1112 printf(" %s\n", "-e, --retries=INTEGER");
1113 printf(" %s%i\n", _("Number of retries to be used in the requests, default: "),
1114 DEFAULT_RETRIES);
1115
1116 printf(" %s\n", "-O, --perf-oids");
1117 printf(" %s\n", _("Label performance data with OIDs instead of --label's"));
1349 1118
1350 printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'")); 1119 printf(" %s\n", "--ignore-mib-parsing-errors");
1351 printf (" %s\n", _("- Note that only one string and one regex may be checked at present")); 1120 printf(" %s\n", _("Do to not print errors encountered when parsing MIB files"));
1352 printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value")); 1121
1353 printf (" %s\n", _("returned from the SNMP query is an unsigned integer.")); 1122 printf(UT_VERBOSE);
1354 1123
1355 printf("\n"); 1124 printf("\n");
1356 printf("%s\n", _("Rate Calculation:")); 1125 printf("%s\n", _("This plugin relies (links against) on the NET-SNMP libraries."));
1357 printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when")); 1126 printf("%s\n",
1358 printf(" %s\n", _("calculating the counter difference since the last check. check_snmp")); 1127 _("if you don't have the libraries installed, you will need to download them from"));
1359 printf(" %s\n", _("saves the last state information in a file so that the rate per second")); 1128 printf("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
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."));
1364
1365 printf (UT_SUPPORT);
1366}
1367 1129
1130 printf("\n");
1131 printf("%s\n", _("Notes:"));
1132 printf(" %s\n",
1133 _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited "));
1134 printf(" %s\n", _("list (lists with internal spaces must be quoted)."));
1368 1135
1136 printf(" -%s", UT_THRESHOLDS_NOTES);
1137
1138 printf(" %s\n",
1139 _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1140 printf(" %s\n", _("- Note that only one string and one regex may be checked at present"));
1141 printf(" %s\n",
1142 _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1143 printf(" %s\n", _("returned from the SNMP query is an unsigned integer."));
1144
1145 printf(UT_SUPPORT);
1146}
1369 1147
1370void 1148void print_usage(void) {
1371print_usage (void) 1149 printf("%s\n", _("Usage:"));
1372{ 1150 printf("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n", progname);
1373 printf ("%s\n", _("Usage:")); 1151 printf("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1374 printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname); 1152 printf("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1375 printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n"); 1153 printf("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n");
1376 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n"); 1154 printf("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n");
1377 printf ("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n"); 1155 printf("[-M multiplier]\n");
1378 printf ("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n");
1379 printf ("[-M multiplier [-f format]]\n");
1380} 1156}