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