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