diff options
author | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-08-25 15:28:04 +0200 |
---|---|---|
committer | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-08-25 15:28:04 +0200 |
commit | 7fe6ac8d08a2baf63db57fd33185224df7e18e27 (patch) | |
tree | 584921e865e31ef6499565fdca0dd37b8b7921ab /plugins/check_snmp.c | |
parent | 723e0d3466d85a6ed9811d0661db289e7d9406d9 (diff) | |
download | monitoring-plugins-7fe6ac8d08a2baf63db57fd33185224df7e18e27.tar.gz |
rebuild check_snmp
Diffstat (limited to 'plugins/check_snmp.c')
-rw-r--r-- | plugins/check_snmp.c | 1654 |
1 files changed, 728 insertions, 926 deletions
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"; | |||
32 | const char *copyright = "1999-2024"; | 32 | const char *copyright = "1999-2024"; |
33 | const char *email = "devel@monitoring-plugins.org"; | 33 | const 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 | |||
67 | const char DEFAULT_COMMUNITY[] = "public"; | ||
68 | const 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 | 80 | typedef 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 | ||
95 | static int process_arguments(int, char **); | 85 | static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/); |
96 | static int validate_arguments(void); | 86 | char *trim_whitespaces_and_check_quoting(char *str); |
97 | static char *thisarg(char *str); | 87 | char *get_next_argument(char *str); |
98 | static char *nextarg(char *str); | ||
99 | void print_usage(void); | 88 | void print_usage(void); |
100 | static void print_help(void); | 89 | void print_help(void); |
101 | static char *multiply(char *str); | 90 | char *multiply(char *str, double multiplier, char *fmt_str); |
102 | 91 | ||
103 | #include "regex.h" | ||
104 | static char regex_expect[MAX_INPUT_BUFFER] = ""; | ||
105 | static regex_t preg; | ||
106 | static regmatch_t pmatch[10]; | ||
107 | static char errbuf[MAX_INPUT_BUFFER] = ""; | ||
108 | static char perfstr[MAX_INPUT_BUFFER] = "| "; | ||
109 | static int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; | ||
110 | static int eflags = 0; | ||
111 | static int errcode, excode; | ||
112 | |||
113 | static char *server_address = NULL; | ||
114 | static char *community = NULL; | ||
115 | static char **contextargs = NULL; | ||
116 | static char *context = NULL; | ||
117 | static char **authpriv = NULL; | ||
118 | static char *proto = NULL; | ||
119 | static char *seclevel = NULL; | ||
120 | static char *secname = NULL; | ||
121 | static char *authproto = NULL; | ||
122 | static char *privproto = NULL; | ||
123 | static char *authpasswd = NULL; | ||
124 | static char *privpasswd = NULL; | ||
125 | static int nulloid = STATE_UNKNOWN; | ||
126 | static char **oids = NULL; | ||
127 | static size_t oids_size = 0; | ||
128 | static char *label; | ||
129 | static char *units; | ||
130 | static char *port; | ||
131 | static char *snmpcmd; | ||
132 | static char string_value[MAX_INPUT_BUFFER] = ""; | ||
133 | static int invert_search = 0; | ||
134 | static char **labels = NULL; | ||
135 | static char **unitv = NULL; | ||
136 | static size_t nlabels = 0; | ||
137 | static size_t labels_size = OID_COUNT_STEP; | ||
138 | static size_t nunits = 0; | ||
139 | static size_t unitv_size = OID_COUNT_STEP; | ||
140 | static size_t numoids = 0; | ||
141 | static int numauthpriv = 0; | ||
142 | static int numcontext = 0; | ||
143 | static int verbose = 0; | 92 | static int verbose = 0; |
144 | static bool usesnmpgetnext = false; | ||
145 | static char *warning_thresholds = NULL; | ||
146 | static char *critical_thresholds = NULL; | ||
147 | static thresholds **thlds; | ||
148 | static size_t thlds_size = OID_COUNT_STEP; | ||
149 | static double *response_value; | ||
150 | static size_t response_size = OID_COUNT_STEP; | ||
151 | static int retries = 0; | ||
152 | static int *eval_method; | ||
153 | static size_t eval_size = OID_COUNT_STEP; | ||
154 | static char *delimiter; | ||
155 | static char *output_delim; | ||
156 | static char *miblist = NULL; | ||
157 | static bool needmibs = false; | ||
158 | static int calculate_rate = 0; | ||
159 | static double offset = 0.0; | ||
160 | static int rate_multiplier = 1; | ||
161 | static state_data *previous_state; | ||
162 | static double *previous_value; | ||
163 | static size_t previous_size = OID_COUNT_STEP; | ||
164 | static int perf_labels = 1; | ||
165 | static char *ip_version = ""; | ||
166 | static double multiplier = 1.0; | ||
167 | static char *fmtstr = ""; | ||
168 | static bool fmtstr_set = false; | ||
169 | static char buffer[DEFAULT_BUFFER_SIZE]; | ||
170 | static bool ignore_mib_parsing_errors = false; | ||
171 | |||
172 | static 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 | ||
194 | int main(int argc, char **argv) { | 94 | int 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(¤t_time); | 112 | time(¤t_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 | } | 393 | static 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++) { |
685 | int 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 | ||
1010 | the authentication and authorization combinations based on protocol version | ||
1011 | selected.</para> | ||
1012 | |||
1013 | <para></para> | ||
1014 | |||
1015 | </sect3> | ||
1016 | -@@ | ||
1017 | ******************************************************************************/ | ||
1018 | 805 | ||
1019 | static 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 | 921 | char *trim_whitespaces_and_check_quoting(char *str) { | |
1122 | static 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 | ||
1135 | static char *nextarg(char *str) { | 935 | char *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) */ |
1161 | static char *multiply(char *str) { | 959 | char *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 | ||
1194 | static void print_help(void) { | 1005 | void 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 | ||