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