From 7fe6ac8d08a2baf63db57fd33185224df7e18e27 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Mon, 25 Aug 2025 15:28:04 +0200 Subject: rebuild check_snmp --- plugins/check_snmp.c | 1654 ++++++++++++++++++++++---------------------------- 1 file changed, 728 insertions(+), 926 deletions(-) (limited to 'plugins/check_snmp.c') diff --git a/plugins/check_snmp.c b/plugins/check_snmp.c index c1d8e2dd..6c9ed959 100644 --- a/plugins/check_snmp.c +++ b/plugins/check_snmp.c @@ -32,222 +32,71 @@ const char *progname = "check_snmp"; const char *copyright = "1999-2024"; const char *email = "devel@monitoring-plugins.org"; -#include "common.h" -#include "runcmd.h" -#include "utils.h" -#include "utils_cmd.h" - -#define DEFAULT_COMMUNITY "public" -#define DEFAULT_PORT "161" -#define DEFAULT_MIBLIST "ALL" -#define DEFAULT_PROTOCOL "1" -#define DEFAULT_RETRIES 5 -#define DEFAULT_AUTH_PROTOCOL "MD5" -#define DEFAULT_PRIV_PROTOCOL "DES" -#define DEFAULT_DELIMITER "=" -#define DEFAULT_OUTPUT_DELIMITER " " -#define DEFAULT_BUFFER_SIZE 100 - -#define mark(a) ((a) != 0 ? "*" : "") - -#define CHECK_UNDEF 0 -#define CRIT_PRESENT 1 -#define CRIT_STRING 2 -#define CRIT_REGEX 4 -#define WARN_PRESENT 8 - -#define OID_COUNT_STEP 8 +#include "./common.h" +#include "./runcmd.h" +#include "./utils.h" +#include "../lib/states.h" +#include "../lib/utils_cmd.h" +#include "../lib/thresholds.h" +#include "../lib/utils_base.h" +#include "../lib/output.h" +#include "../lib/perfdata.h" + +#include +#include +#include +#include + +#include "check_snmp.d/config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../gl/regex.h" +#include + +const char DEFAULT_COMMUNITY[] = "public"; +const char DEFAULT_MIBLIST[] = "ALL"; +#define DEFAULT_AUTH_PROTOCOL "MD5" +#define DEFAULT_PRIV_PROTOCOL "DES" +#define DEFAULT_DELIMITER "=" +#define DEFAULT_BUFFER_SIZE 100 /* Longopts only arguments */ -#define L_CALCULATE_RATE CHAR_MAX + 1 -#define L_RATE_MULTIPLIER CHAR_MAX + 2 #define L_INVERT_SEARCH CHAR_MAX + 3 #define L_OFFSET CHAR_MAX + 4 #define L_IGNORE_MIB_PARSING_ERRORS CHAR_MAX + 5 +#define L_CONNECTION_PREFIX CHAR_MAX + 6 -/* Gobble to string - stop incrementing c when c[0] match one of the - * characters in s */ -#define GOBBLE_TOS(c, s) \ - while (c[0] != '\0' && strchr(s, c[0]) == NULL) { \ - c++; \ - } -/* Given c, keep track of backslashes (bk) and double-quotes (dq) - * from c[0] */ -#define COUNT_SEQ(c, bk, dq) \ - switch (c[0]) { \ - case '\\': \ - if (bk) \ - bk--; \ - else \ - bk++; \ - break; \ - case '"': \ - if (!dq) { \ - dq++; \ - } else if (!bk) { \ - dq--; \ - } else { \ - bk--; \ - } \ - break; \ - } +typedef struct proces_arguments_wrapper { + int errorcode; + check_snmp_config config; +} process_arguments_wrapper; -static int process_arguments(int, char **); -static int validate_arguments(void); -static char *thisarg(char *str); -static char *nextarg(char *str); +static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/); +char *trim_whitespaces_and_check_quoting(char *str); +char *get_next_argument(char *str); void print_usage(void); -static void print_help(void); -static char *multiply(char *str); - -#include "regex.h" -static char regex_expect[MAX_INPUT_BUFFER] = ""; -static regex_t preg; -static regmatch_t pmatch[10]; -static char errbuf[MAX_INPUT_BUFFER] = ""; -static char perfstr[MAX_INPUT_BUFFER] = "| "; -static int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; -static int eflags = 0; -static int errcode, excode; - -static char *server_address = NULL; -static char *community = NULL; -static char **contextargs = NULL; -static char *context = NULL; -static char **authpriv = NULL; -static char *proto = NULL; -static char *seclevel = NULL; -static char *secname = NULL; -static char *authproto = NULL; -static char *privproto = NULL; -static char *authpasswd = NULL; -static char *privpasswd = NULL; -static int nulloid = STATE_UNKNOWN; -static char **oids = NULL; -static size_t oids_size = 0; -static char *label; -static char *units; -static char *port; -static char *snmpcmd; -static char string_value[MAX_INPUT_BUFFER] = ""; -static int invert_search = 0; -static char **labels = NULL; -static char **unitv = NULL; -static size_t nlabels = 0; -static size_t labels_size = OID_COUNT_STEP; -static size_t nunits = 0; -static size_t unitv_size = OID_COUNT_STEP; -static size_t numoids = 0; -static int numauthpriv = 0; -static int numcontext = 0; +void print_help(void); +char *multiply(char *str, double multiplier, char *fmt_str); + static int verbose = 0; -static bool usesnmpgetnext = false; -static char *warning_thresholds = NULL; -static char *critical_thresholds = NULL; -static thresholds **thlds; -static size_t thlds_size = OID_COUNT_STEP; -static double *response_value; -static size_t response_size = OID_COUNT_STEP; -static int retries = 0; -static int *eval_method; -static size_t eval_size = OID_COUNT_STEP; -static char *delimiter; -static char *output_delim; -static char *miblist = NULL; -static bool needmibs = false; -static int calculate_rate = 0; -static double offset = 0.0; -static int rate_multiplier = 1; -static state_data *previous_state; -static double *previous_value; -static size_t previous_size = OID_COUNT_STEP; -static int perf_labels = 1; -static char *ip_version = ""; -static double multiplier = 1.0; -static char *fmtstr = ""; -static bool fmtstr_set = false; -static char buffer[DEFAULT_BUFFER_SIZE]; -static bool ignore_mib_parsing_errors = false; - -static char *fix_snmp_range(char *th) { - double left; - double right; - char *colon; - char *ret; - - if ((colon = strchr(th, ':')) == NULL || *(colon + 1) == '\0') - return th; - - left = strtod(th, NULL); - right = strtod(colon + 1, NULL); - if (right >= left) - return th; - - if ((ret = malloc(strlen(th) + 2)) == NULL) - die(STATE_UNKNOWN, _("Cannot malloc")); - *colon = '\0'; - sprintf(ret, "@%s:%s", colon + 1, th); - free(th); - return ret; -} int main(int argc, char **argv) { - int len; - int total_oids; - size_t line; - unsigned int bk_count = 0; - unsigned int dq_count = 0; - int iresult = STATE_UNKNOWN; - int result = STATE_UNKNOWN; - int return_code = 0; - int external_error = 0; - char **command_line = NULL; - char *cl_hidden_auth = NULL; - char *oidname = NULL; - char *response = NULL; - char *mult_resp = NULL; - char *outbuff; - char *ptr = NULL; - char *show = NULL; - char *th_warn = NULL; - char *th_crit = NULL; - char type[8] = ""; - output chld_out; - output chld_err; - char *previous_string = NULL; - char *ap = NULL; - char *state_string = NULL; - size_t response_length; - size_t current_length; - size_t string_length; - char *temp_string = NULL; - char *quote_string = NULL; - time_t current_time; - double temp_double; - time_t duration; - char *conv = "12345678"; - int is_counter = 0; - setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); - labels = malloc(labels_size * sizeof(*labels)); - unitv = malloc(unitv_size * sizeof(*unitv)); - thlds = malloc(thlds_size * sizeof(*thlds)); - response_value = malloc(response_size * sizeof(*response_value)); - previous_value = malloc(previous_size * sizeof(*previous_value)); - eval_method = calloc(eval_size, sizeof(*eval_method)); - oids = calloc(oids_size, sizeof(char *)); - - label = strdup("SNMP"); - units = strdup(""); - port = strdup(DEFAULT_PORT); - outbuff = strdup(""); - delimiter = strdup(" = "); - output_delim = strdup(DEFAULT_OUTPUT_DELIMITER); timeout_interval = DEFAULT_SOCKET_TIMEOUT; - retries = DEFAULT_RETRIES; np_init((char *)progname, argc, argv); @@ -256,492 +105,416 @@ int main(int argc, char **argv) { np_set_args(argc, argv); + // Initialize net-snmp before touching the sessio we are going to use + init_snmp("check_snmp"); + + time_t current_time; time(¤t_time); - if (process_arguments(argc, argv) == ERROR) + process_arguments_wrapper paw_tmp = process_arguments(argc, argv); + if (paw_tmp.errorcode == ERROR) { usage4(_("Could not parse arguments")); - - if (calculate_rate) { - if (!strcmp(label, "SNMP")) - label = strdup("SNMP RATE"); - - size_t i = 0; - - previous_state = np_state_read(); - if (previous_state != NULL) { - /* Split colon separated values */ - previous_string = strdup((char *)previous_state->data); - while ((ap = strsep(&previous_string, ":")) != NULL) { - if (verbose > 2) - printf("State for %zd=%s\n", i, ap); - while (i >= previous_size) { - previous_size += OID_COUNT_STEP; - previous_value = realloc(previous_value, previous_size * sizeof(*previous_value)); - } - previous_value[i++] = strtod(ap, NULL); - } - } } - /* Populate the thresholds */ - th_warn = warning_thresholds; - th_crit = critical_thresholds; - for (size_t i = 0; i < numoids; i++) { - char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL; - char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL; - /* translate "2:1" to "@1:2" for backwards compatibility */ - w = w ? fix_snmp_range(w) : NULL; - c = c ? fix_snmp_range(c) : NULL; - - while (i >= thlds_size) { - thlds_size += OID_COUNT_STEP; - thlds = realloc(thlds, thlds_size * sizeof(*thlds)); - } + check_snmp_config config = paw_tmp.config; - /* Skip empty thresholds, while avoiding segfault */ - set_thresholds(&thlds[i], w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL, c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL); - if (w) { - th_warn = strchr(th_warn, ','); - if (th_warn) - th_warn++; - free(w); - } - if (c) { - th_crit = strchr(th_crit, ','); - if (th_crit) - th_crit++; - free(c); + if (config.ignore_mib_parsing_errors) { + char *opt_toggle_res = snmp_mib_toggle_options("e"); + if (opt_toggle_res != NULL) { + die(STATE_UNKNOWN, "Unable to disable MIB parsing errors"); } } - /* Create the command array to execute */ - if (usesnmpgetnext) { - snmpcmd = strdup(PATH_TO_SNMPGETNEXT); + struct snmp_pdu *pdu = NULL; + if (config.use_getnext) { + pdu = snmp_pdu_create(SNMP_MSG_GETNEXT); } else { - snmpcmd = strdup(PATH_TO_SNMPGET); + pdu = snmp_pdu_create(SNMP_MSG_GET); } - /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */ - - unsigned index = 0; - command_line = calloc(11 + numcontext + numauthpriv + 1 + numoids + 1, sizeof(char *)); - - command_line[index++] = snmpcmd; - command_line[index++] = strdup("-Le"); - command_line[index++] = strdup("-t"); - xasprintf(&command_line[index++], "%d", timeout_interval); - command_line[index++] = strdup("-r"); - xasprintf(&command_line[index++], "%d", retries); - command_line[index++] = strdup("-m"); - command_line[index++] = strdup(miblist); - command_line[index++] = "-v"; - command_line[index++] = strdup(proto); - - xasprintf(&cl_hidden_auth, "%s -Le -t %d -r %d -m %s -v %s", snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''", - proto); - - if (ignore_mib_parsing_errors) { - command_line[index++] = "-Pe"; - xasprintf(&cl_hidden_auth, "%s -Pe", cl_hidden_auth); - } + for (size_t i = 0; i < config.num_of_test_units; i++) { + assert(config.test_units[i].oid != NULL); + if (verbose > 0) { + printf("OID %zu to parse: %s\n", i, config.test_units[i].oid); + } - for (int i = 0; i < numcontext; i++) { - command_line[index++] = contextargs[i]; + oid tmp_OID[MAX_OID_LEN]; + size_t tmp_OID_len = MAX_OID_LEN; + if (snmp_parse_oid(config.test_units[i].oid, tmp_OID, &tmp_OID_len) != NULL) { + // success + snmp_add_null_var(pdu, tmp_OID, tmp_OID_len); + } else { + // failed + snmp_perror("Parsing failure"); + die(STATE_UNKNOWN, "Failed to parse OID\n"); + } } - for (int i = 0; i < numauthpriv; i++) { - command_line[index++] = authpriv[i]; + /* Set signal handling and alarm */ + if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) { + usage4(_("Cannot catch SIGALRM")); } - xasprintf(&command_line[index++], "%s:%s", server_address, port); - - xasprintf(&cl_hidden_auth, "%s [context] [authpriv] %s:%s", cl_hidden_auth, server_address, port); + const int timeout_safety_tolerance = 5; + alarm(timeout_interval * config.snmp_session.retries + timeout_safety_tolerance); - for (size_t i = 0; i < numoids; i++) { - command_line[index++] = oids[i]; - xasprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]); + struct snmp_session *active_session = snmp_open(&config.snmp_session); + if (active_session == NULL) { + snmp_sess_perror("Failed to open session", &config.snmp_session); + die(STATE_UNKNOWN, "Failed to open SNMP session\n"); } - command_line[index++] = NULL; + struct snmp_pdu *response = NULL; + int snmp_query_status = snmp_synch_response(active_session, pdu, &response); - if (verbose) { - printf("%s\n", cl_hidden_auth); + if (!(snmp_query_status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR)) { + snmp_sess_perror("Failed to query", active_session); + // FAILED somehow + // TODO do some error analysis here + die(STATE_UNKNOWN, "SNMP query failed\n"); } - /* Set signal handling and alarm */ - if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) { - usage4(_("Cannot catch SIGALRM")); - } - alarm(timeout_interval * retries + 5); - - /* Run the command */ - return_code = cmd_run_array(command_line, &chld_out, &chld_err, 0); + snmp_close(active_session); /* disable alarm again */ alarm(0); - /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs, - only return state unknown if return code is non zero or there is no stdout. - Do this way so that if there is stderr, will get added to output, which helps problem diagnosis - */ - if (return_code != 0) - external_error = 1; - if (chld_out.lines == 0) - external_error = 1; - if (external_error) { - if (chld_err.lines > 0) { - printf(_("External command error: %s\n"), chld_err.line[0]); - for (size_t i = 1; i < chld_err.lines; i++) { - printf("%s\n", chld_err.line[i]); - } - } else { - printf(_("External command error with no output (return code: %d)\n"), return_code); + mp_check overall = mp_check_init(); + + mp_subcheck sc_succesfull_query = mp_subcheck_init(); + xasprintf(&sc_succesfull_query.output, "SNMP query was succesful"); + sc_succesfull_query = mp_set_subcheck_state(sc_succesfull_query, STATE_OK); + mp_add_subcheck_to_check(&overall, sc_succesfull_query); + + // We got the the query results, now process them + size_t loop_index = 0; + for (netsnmp_variable_list *vars = response->variables; vars; + vars = vars->next_variable, loop_index++) { + mp_subcheck sc_oid_test = mp_subcheck_init(); + + if (verbose > 0) { + printf("loop_index: %zu\n", loop_index); } - exit(STATE_UNKNOWN); - } - if (verbose) { - for (size_t i = 0; i < chld_out.lines; i++) { - printf("%s\n", chld_out.line[i]); + if ((config.test_units[loop_index].label != NULL) && + (strcmp(config.test_units[loop_index].label, "") != 0)) { + xasprintf(&sc_oid_test.output, "%s - ", config.test_units[loop_index].label); + } else { + sc_oid_test.output = strdup(""); } - } - line = 0; - total_oids = 0; - for (size_t i = 0; line < chld_out.lines && i < numoids; line++, i++, total_oids++) { - if (calculate_rate) - conv = "%.10g"; - else - conv = "%.0f"; - - ptr = chld_out.line[line]; - oidname = strpcpy(oidname, ptr, delimiter); - response = strstr(ptr, delimiter); - if (response == NULL) - break; + char oid_string[(MAX_OID_LEN * 2) + 1]; + memset(oid_string, 0, (MAX_OID_LEN * 2) + 1); + + int oid_string_result = + snprint_objid(oid_string, (MAX_OID_LEN * 2) + 1, vars->name, vars->name_length); + if (oid_string_result <= 0) { + // TODO error here + } if (verbose > 2) { - printf("Processing oid %zi (line %zi)\n oidname: %s\n response: %s\n", i + 1, line + 1, oidname, response); + printf("Processing oid %s\n", oid_string); } - /* Clean up type array - Sol10 does not necessarily zero it out */ - bzero(type, sizeof(type)); - - is_counter = 0; - /* We strip out the datatype indicator for PHBs */ - if (strstr(response, "Gauge: ")) { - show = multiply(strstr(response, "Gauge: ") + 7); - } else if (strstr(response, "Gauge32: ")) { - show = multiply(strstr(response, "Gauge32: ") + 9); - } else if (strstr(response, "Counter32: ")) { - show = strstr(response, "Counter32: ") + 11; - is_counter = 1; - if (!calculate_rate) - strcpy(type, "c"); - } else if (strstr(response, "Counter64: ")) { - show = strstr(response, "Counter64: ") + 11; - is_counter = 1; - if (!calculate_rate) - strcpy(type, "c"); - } else if (strstr(response, "INTEGER: ")) { - show = multiply(strstr(response, "INTEGER: ") + 9); - - if (fmtstr_set) { - conv = fmtstr; + mp_perfdata_value pd_result_val = {0}; + xasprintf(&sc_oid_test.output, "%sOID: %s", sc_oid_test.output, oid_string); + sc_oid_test = mp_set_subcheck_default_state(sc_oid_test, STATE_OK); + + switch (vars->type) { + case ASN_OCTET_STR: { + if (verbose) { + printf("Debug: Got a string\n"); } - } else if (strstr(response, "OID: ")) { - show = strstr(response, "OID: ") + 5; - } else if (strstr(response, "STRING: ")) { - show = strstr(response, "STRING: ") + 8; - conv = "%.10g"; - - /* Get the rest of the string on multi-line strings */ - ptr = show; - COUNT_SEQ(ptr, bk_count, dq_count) - while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') { - ptr++; - GOBBLE_TOS(ptr, "\n\"\\") - COUNT_SEQ(ptr, bk_count, dq_count) + char *tmp = (char *)vars->val.string; + xasprintf(&sc_oid_test.output, "%s - Value: %s", sc_oid_test.output, tmp); + + if (strlen(tmp) == 0) { + sc_oid_test = mp_set_subcheck_state(sc_oid_test, config.nulloid_result); } - if (dq_count) { /* unfinished line */ - /* copy show verbatim first */ - if (!mult_resp) - mult_resp = strdup(""); - xasprintf(&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show); - /* then strip out unmatched double-quote from single-line output */ - if (show[0] == '"') - show++; - - /* Keep reading until we match end of double-quoted string */ - for (line++; line < chld_out.lines; line++) { - ptr = chld_out.line[line]; - xasprintf(&mult_resp, "%s%s\n", mult_resp, ptr); - - COUNT_SEQ(ptr, bk_count, dq_count) - while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') { - ptr++; - GOBBLE_TOS(ptr, "\n\"\\") - COUNT_SEQ(ptr, bk_count, dq_count) - } - /* Break for loop before next line increment when done */ - if (!dq_count) - break; + // String matching test + if ((config.test_units[loop_index].eval_mthd.crit_string)) { + if (strcmp(tmp, config.string_cmp_value)) { + sc_oid_test = mp_set_subcheck_state( + sc_oid_test, (config.invert_search) ? STATE_CRITICAL : STATE_OK); + } else { + sc_oid_test = mp_set_subcheck_state( + sc_oid_test, (config.invert_search) ? STATE_OK : STATE_CRITICAL); + } + } else if (config.test_units[loop_index].eval_mthd.crit_regex) { + const int nmatch = config.regex_cmp_value.re_nsub + 1; + regmatch_t pmatch[nmatch]; + memset(pmatch, '\0', sizeof(regmatch_t) * nmatch); + + int excode = regexec(&config.regex_cmp_value, tmp, nmatch, pmatch, 0); + if (excode == 0) { + sc_oid_test = mp_set_subcheck_state( + sc_oid_test, (config.invert_search) ? STATE_OK : STATE_CRITICAL); + } else if (excode != REG_NOMATCH) { + char errbuf[MAX_INPUT_BUFFER] = ""; + regerror(excode, &config.regex_cmp_value, errbuf, MAX_INPUT_BUFFER); + printf(_("Execute Error: %s\n"), errbuf); + exit(STATE_CRITICAL); + } else { // REG_NOMATCH + sc_oid_test = mp_set_subcheck_state( + sc_oid_test, config.invert_search ? STATE_CRITICAL : STATE_OK); } } - } else if (strstr(response, "Timeticks: ")) { - show = strstr(response, "Timeticks: "); - } else - show = response + 3; - - iresult = STATE_DEPENDENT; + mp_add_subcheck_to_check(&overall, sc_oid_test); + } + continue; + case ASN_OPAQUE: + if (verbose) { + printf("Debug: Got OPAQUE\n"); + } + break; + case ASN_COUNTER64: { + if (verbose) { + printf("Debug: Got counter64\n"); + } + struct counter64 tmp = *(vars->val.counter64); + uint64_t counter = (tmp.high << 32) + tmp.low; + counter *= config.multiplier; + counter += config.offset; + pd_result_val = mp_create_pd_value(counter); + } break; + /* Numerical values */ + case ASN_GAUGE: // same as ASN_UNSIGNED + case ASN_TIMETICKS: + case ASN_COUNTER: + case ASN_UINTEGER: { + if (verbose) { + printf("Debug: Got a Integer like\n"); + } + unsigned long tmp = *(vars->val.integer); + tmp *= config.multiplier; - /* Process this block for numeric comparisons */ - /* Make some special values,like Timeticks numeric only if a threshold is defined */ - if (thlds[i]->warning || thlds[i]->critical || calculate_rate) { - if (verbose > 2) { - print_thresholds(" thresholds", thlds[i]); + tmp += config.offset; + pd_result_val = mp_create_pd_value(tmp); + break; + } + case ASN_INTEGER: { + if (verbose) { + printf("Debug: Got a Integer\n"); } - ptr = strpbrk(show, "-0123456789"); - if (ptr == NULL) { - if (nulloid == 3) - die(STATE_UNKNOWN, _("No valid data returned (%s)\n"), show); - else if (nulloid == 0) - die(STATE_OK, _("No valid data returned (%s)\n"), show); - else if (nulloid == 1) - die(STATE_WARNING, _("No valid data returned (%s)\n"), show); - else if (nulloid == 2) - die(STATE_CRITICAL, _("No valid data returned (%s)\n"), show); + unsigned long tmp = *(vars->val.integer); + tmp *= config.multiplier; + + tmp += config.offset; + pd_result_val = mp_create_pd_value(tmp); + } break; + case ASN_FLOAT: { + if (verbose) { + printf("Debug: Got a float\n"); } - while (i >= response_size) { - response_size += OID_COUNT_STEP; - response_value = realloc(response_value, response_size * sizeof(*response_value)); + float tmp = *(vars->val.floatVal); + tmp *= config.multiplier; + + tmp += config.offset; + pd_result_val = mp_create_pd_value(tmp); + break; + } + case ASN_DOUBLE: { + if (verbose) { + printf("Debug: Got a double\n"); } - response_value[i] = strtod(ptr, NULL) + offset; - - if (calculate_rate) { - if (previous_state != NULL) { - duration = current_time - previous_state->time; - if (duration <= 0) - die(STATE_UNKNOWN, _("Time duration between plugin calls is invalid")); - temp_double = response_value[i] - previous_value[i]; - /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */ - if (is_counter) { - if (temp_double < (double)0.0) - temp_double += (double)4294967296.0; /* 2^32 */ - if (temp_double < (double)0.0) - temp_double += (double)18446744069414584320.0; /* 2^64-2^32 */ - ; - } - /* Convert to per second, then use multiplier */ - temp_double = temp_double / duration * rate_multiplier; - iresult = get_status(temp_double, thlds[i]); - xasprintf(&show, conv, temp_double); - } - } else { - iresult = get_status(response_value[i], thlds[i]); - xasprintf(&show, conv, response_value[i]); + double tmp = *(vars->val.doubleVal); + tmp *= config.multiplier; + tmp += config.offset; + pd_result_val = mp_create_pd_value(tmp); + break; + } + case ASN_IPADDRESS: + if (verbose) { + printf("Debug: Got an IP address\n"); } + continue; + default: + if (verbose) { + printf("Debug: Got a unmatched result type: %hhu\n", vars->type); + } + // TODO: Error here? + continue; } - /* Process this block for string matching */ - else if (eval_size > i && eval_method[i] & CRIT_STRING) { - if (strcmp(show, string_value)) - iresult = (invert_search == 0) ? STATE_CRITICAL : STATE_OK; - else - iresult = (invert_search == 0) ? STATE_OK : STATE_CRITICAL; + // some kind of numerical value + mp_perfdata pd_num_val = { + .value = pd_result_val, + }; + + if (!config.use_perf_data_labels_from_input) { + // Use oid for perdata label + pd_num_val.label = strdup(oid_string); + // TODO strdup error checking + } else if (config.test_units[loop_index].label != NULL || + strcmp(config.test_units[loop_index].label, "") != 0) { + pd_num_val.label = config.test_units[loop_index].label; } - /* Process this block for regex matching */ - else if (eval_size > i && eval_method[i] & CRIT_REGEX) { - excode = regexec(&preg, response, 10, pmatch, eflags); - if (excode == 0) { - iresult = (invert_search == 0) ? STATE_OK : STATE_CRITICAL; - } else if (excode != REG_NOMATCH) { - regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER); - printf(_("Execute Error: %s\n"), errbuf); - exit(STATE_CRITICAL); - } else { - iresult = (invert_search == 0) ? STATE_CRITICAL : STATE_OK; - } + if (config.test_units[loop_index].unit_value != NULL && + strcmp(config.test_units[loop_index].unit_value, "") != 0) { + pd_num_val.uom = config.test_units[loop_index].unit_value; } - /* Process this block for existence-nonexistence checks */ - /* TV: Should this be outside of this else block? */ - else { - if (eval_size > i && eval_method[i] & CRIT_PRESENT) - iresult = STATE_CRITICAL; - else if (eval_size > i && eval_method[i] & WARN_PRESENT) - iresult = STATE_WARNING; - else if (response && iresult == STATE_DEPENDENT) - iresult = STATE_OK; + xasprintf(&sc_oid_test.output, "%s Value: %s", sc_oid_test.output, + pd_value_to_string(pd_result_val)); + + if (config.test_units[loop_index].unit_value != NULL && + strcmp(config.test_units[loop_index].unit_value, "") != 0) { + xasprintf(&sc_oid_test.output, "%s%s", sc_oid_test.output, + config.test_units[loop_index].unit_value); } - /* Result is the worst outcome of all the OIDs tested */ - result = max_state(result, iresult); - - /* Prepend a label for this OID if there is one */ - if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL) - xasprintf(&outbuff, "%s%s%s %s%s%s", outbuff, (i == 0) ? " " : output_delim, labels[i], mark(iresult), show, mark(iresult)); - else - xasprintf(&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim, mark(iresult), show, mark(iresult)); - - /* Append a unit string for this OID if there is one */ - if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL) - xasprintf(&outbuff, "%s %s", outbuff, unitv[i]); - - /* Write perfdata with whatever can be parsed by strtod, if possible */ - ptr = NULL; - strtod(show, &ptr); - if (ptr > show) { - if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL) - temp_string = labels[i]; - else - temp_string = oidname; - if (strpbrk(temp_string, " ='\"") == NULL) { - strncat(perfstr, temp_string, sizeof(perfstr) - strlen(perfstr) - 1); - } else { - if (strpbrk(temp_string, "'") == NULL) { - quote_string = "'"; - } else { - quote_string = "\""; - } - strncat(perfstr, quote_string, sizeof(perfstr) - strlen(perfstr) - 1); - strncat(perfstr, temp_string, sizeof(perfstr) - strlen(perfstr) - 1); - strncat(perfstr, quote_string, sizeof(perfstr) - strlen(perfstr) - 1); + if (config.thresholds.warning_is_set || config.thresholds.critical_is_set) { + pd_num_val = mp_pd_set_thresholds(pd_num_val, config.thresholds); + mp_state_enum tmp_state = mp_get_pd_status(pd_num_val); + + if (tmp_state == STATE_WARNING) { + sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_WARNING); + xasprintf(&sc_oid_test.output, "%s - number violates warning threshold", + sc_oid_test.output); + } else if (tmp_state == STATE_CRITICAL) { + sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_CRITICAL); + xasprintf(&sc_oid_test.output, "%s - number violates critical threshold", + sc_oid_test.output); } - strncat(perfstr, "=", sizeof(perfstr) - strlen(perfstr) - 1); - len = sizeof(perfstr) - strlen(perfstr) - 1; - strncat(perfstr, show, len > ptr - show ? ptr - show : len); + } - if (strcmp(type, "") != 0) { - strncat(perfstr, type, sizeof(perfstr) - strlen(perfstr) - 1); - } + mp_add_perfdata_to_subcheck(&sc_oid_test, pd_num_val); - if (warning_thresholds) { - strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1); - if (thlds[i]->warning && thlds[i]->warning->text) - strncat(perfstr, thlds[i]->warning->text, sizeof(perfstr) - strlen(perfstr) - 1); - } + mp_add_subcheck_to_check(&overall, sc_oid_test); + } - if (critical_thresholds) { - if (!warning_thresholds) - strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1); - strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1); - if (thlds[i]->critical && thlds[i]->critical->text) - strncat(perfstr, thlds[i]->critical->text, sizeof(perfstr) - strlen(perfstr) - 1); - } + mp_exit(overall); +} - strncat(perfstr, " ", sizeof(perfstr) - strlen(perfstr) - 1); - } +/* process command-line arguments */ +static process_arguments_wrapper process_arguments(int argc, char **argv) { + static struct option longopts[] = { + STD_LONG_OPTS, + {"community", required_argument, 0, 'C'}, + {"oid", required_argument, 0, 'o'}, + {"object", required_argument, 0, 'o'}, + {"delimiter", required_argument, 0, 'd'}, + {"nulloid", required_argument, 0, 'z'}, + {"output-delimiter", required_argument, 0, 'D'}, + {"string", required_argument, 0, 's'}, + {"timeout", required_argument, 0, 't'}, + {"regex", required_argument, 0, 'r'}, + {"ereg", required_argument, 0, 'r'}, + {"eregi", required_argument, 0, 'R'}, + {"label", required_argument, 0, 'l'}, + {"units", required_argument, 0, 'u'}, + {"port", required_argument, 0, 'p'}, + {"retries", required_argument, 0, 'e'}, + {"miblist", required_argument, 0, 'm'}, + {"protocol", required_argument, 0, 'P'}, + {"context", required_argument, 0, 'N'}, + {"seclevel", required_argument, 0, 'L'}, + {"secname", required_argument, 0, 'U'}, + {"authproto", required_argument, 0, 'a'}, + {"privproto", required_argument, 0, 'x'}, + {"authpasswd", required_argument, 0, 'A'}, + {"privpasswd", required_argument, 0, 'X'}, + {"next", no_argument, 0, 'n'}, + {"offset", required_argument, 0, L_OFFSET}, + {"invert-search", no_argument, 0, L_INVERT_SEARCH}, + {"perf-oids", no_argument, 0, 'O'}, + {"ipv4", no_argument, 0, '4'}, + {"ipv6", no_argument, 0, '6'}, + {"multiplier", required_argument, 0, 'M'}, + {"ignore-mib-parsing-errors", no_argument, false, L_IGNORE_MIB_PARSING_ERRORS}, + {"connection-prefix", required_argument, 0, L_CONNECTION_PREFIX}, + {0, 0, 0, 0}}; + + if (argc < 2) { + process_arguments_wrapper result = { + .errorcode = ERROR, + }; + return result; } - /* Save state data, as all data collected now */ - if (calculate_rate) { - string_length = 1024; - state_string = malloc(string_length); - if (state_string == NULL) - die(STATE_UNKNOWN, _("Cannot malloc")); - - current_length = 0; - for (int i = 0; i < total_oids; i++) { - xasprintf(&temp_string, "%.0f", response_value[i]); - if (temp_string == NULL) - die(STATE_UNKNOWN, _("Cannot asprintf()")); - response_length = strlen(temp_string); - if (current_length + response_length > string_length) { - string_length = current_length + 1024; - state_string = realloc(state_string, string_length); - if (state_string == NULL) - die(STATE_UNKNOWN, _("Cannot realloc()")); + // Count number of OIDs here first + int option = 0; + size_t oid_counter = 0; + while (true) { + 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); + + if (option_char == -1 || option_char == EOF) { + break; + } + + switch (option_char) { + case 'o': { + // we are going to parse this again, so we work on a copy of that string + char *tmp_oids = strdup(optarg); + if (tmp_oids == NULL) { + die(STATE_UNKNOWN, "strdup failed"); } - strcpy(&state_string[current_length], temp_string); - current_length = current_length + response_length; - state_string[current_length] = ':'; - current_length++; - free(temp_string); + + for (char *ptr = strtok(tmp_oids, ", "); ptr != NULL; + ptr = strtok(NULL, ", "), oid_counter++) { + } + break; } - state_string[--current_length] = '\0'; - if (verbose > 2) - printf("State string=%s\n", state_string); - - /* This is not strictly the same as time now, but any subtle variations will cancel out */ - np_state_write_string(current_time, state_string); - if (previous_state == NULL) { - /* Or should this be highest state? */ - die(STATE_OK, _("No previous data to calculate rate - assume okay")); + case '?': /* usage */ + usage5(); + // fallthrough + case 'h': /* help */ + print_help(); + exit(STATE_UNKNOWN); + case 'V': /* version */ + print_revision(progname, NP_VERSION); + exit(STATE_UNKNOWN); + + default: + continue; } } - printf("%s %s -%s %s\n", label, state_text(result), outbuff, perfstr); - if (mult_resp) - printf("%s", mult_resp); + /* Check whether at least one OID was given */ + if (oid_counter == 0) { + die(STATE_UNKNOWN, _("No OIDs specified\n")); + } - return result; -} + // Allocate space for test units + check_snmp_test_unit *tmp = calloc(oid_counter, sizeof(check_snmp_test_unit)); + if (tmp == NULL) { + die(STATE_UNKNOWN, "Failed to calloc"); + } -/* process command-line arguments */ -int process_arguments(int argc, char **argv) { - static struct option longopts[] = {STD_LONG_OPTS, - {"community", required_argument, 0, 'C'}, - {"oid", required_argument, 0, 'o'}, - {"object", required_argument, 0, 'o'}, - {"delimiter", required_argument, 0, 'd'}, - {"nulloid", required_argument, 0, 'z'}, - {"output-delimiter", required_argument, 0, 'D'}, - {"string", required_argument, 0, 's'}, - {"timeout", required_argument, 0, 't'}, - {"regex", required_argument, 0, 'r'}, - {"ereg", required_argument, 0, 'r'}, - {"eregi", required_argument, 0, 'R'}, - {"label", required_argument, 0, 'l'}, - {"units", required_argument, 0, 'u'}, - {"port", required_argument, 0, 'p'}, - {"retries", required_argument, 0, 'e'}, - {"miblist", required_argument, 0, 'm'}, - {"protocol", required_argument, 0, 'P'}, - {"context", required_argument, 0, 'N'}, - {"seclevel", required_argument, 0, 'L'}, - {"secname", required_argument, 0, 'U'}, - {"authproto", required_argument, 0, 'a'}, - {"privproto", required_argument, 0, 'x'}, - {"authpasswd", required_argument, 0, 'A'}, - {"privpasswd", required_argument, 0, 'X'}, - {"next", no_argument, 0, 'n'}, - {"rate", no_argument, 0, L_CALCULATE_RATE}, - {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER}, - {"offset", required_argument, 0, L_OFFSET}, - {"invert-search", no_argument, 0, L_INVERT_SEARCH}, - {"perf-oids", no_argument, 0, 'O'}, - {"ipv4", no_argument, 0, '4'}, - {"ipv6", no_argument, 0, '6'}, - {"multiplier", required_argument, 0, 'M'}, - {"fmtstr", required_argument, 0, 'f'}, - {"ignore-mib-parsing-errors", no_argument, false, L_IGNORE_MIB_PARSING_ERRORS}, - {0, 0, 0, 0}}; - - if (argc < 2) - return ERROR; - - /* reverse compatibility for very old non-POSIX usage forms */ - for (int c = 1; c < argc; c++) { - if (strcmp("-to", argv[c]) == 0) - strcpy(argv[c], "-t"); - if (strcmp("-wv", argv[c]) == 0) - strcpy(argv[c], "-w"); - if (strcmp("-cv", argv[c]) == 0) - strcpy(argv[c], "-c"); + for (size_t i = 0; i < oid_counter; i++) { + tmp[i] = check_snmp_test_unit_init(); } - size_t j = 0; - size_t jj = 0; + check_snmp_config config = check_snmp_config_init(); + config.test_units = tmp; + config.num_of_test_units = oid_counter; + + option = 0; + optind = 1; // Reset argument scanner + size_t tmp_oid_counter = 0; + size_t eval_counter = 0; + size_t unitv_counter = 0; + size_t labels_counter = 0; + unsigned char *authpasswd = NULL; + unsigned char *privpasswd = NULL; + int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; + char *port = NULL; + char *miblist = NULL; + char *connection_prefix = NULL; + // TODO error checking while (true) { - int option = 0; - 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); + 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); - if (option_char == -1 || option_char == EOF) + if (option_char == -1 || option_char == EOF) { break; + } switch (option_char) { case '?': /* usage */ @@ -758,65 +531,152 @@ int process_arguments(int argc, char **argv) { /* Connection info */ case 'C': /* group or community */ - community = optarg; + config.snmp_session.community = (unsigned char *)optarg; + config.snmp_session.community_len = strlen(optarg); break; case 'H': /* Host or server */ - server_address = optarg; + config.snmp_session.peername = optarg; break; - case 'p': /* TCP port number */ + case 'p': /*port number */ + // Add port to "peername" below to not rely on argument order port = optarg; break; case 'm': /* List of MIBS */ miblist = optarg; break; - case 'n': /* usesnmpgetnext */ - usesnmpgetnext = true; + case 'n': /* use_getnext instead of get */ + config.use_getnext = true; break; case 'P': /* SNMP protocol version */ - proto = optarg; + if (strcasecmp("1", optarg) == 0) { + config.snmp_session.version = SNMP_VERSION_1; + } else if (strcasecmp("2c", optarg) == 0) { + config.snmp_session.version = SNMP_VERSION_2c; + } else if (strcasecmp("3", optarg) == 0) { + config.snmp_session.version = SNMP_VERSION_3; + } else { + die(STATE_UNKNOWN, "invalid SNMP version/protocol: %s", optarg); + } break; - case 'N': /* SNMPv3 context */ - context = optarg; + case 'N': /* SNMPv3 context name */ + config.snmp_session.contextName = optarg; + config.snmp_session.contextNameLen = strlen(optarg); break; case 'L': /* security level */ - seclevel = optarg; + if (strcasecmp("noAuthNoPriv", optarg) == 0) { + config.snmp_session.securityLevel = SNMP_SEC_LEVEL_NOAUTH; + } else if (strcasecmp("authNoPriv", optarg) == 0) { + config.snmp_session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV; + } else if (strcasecmp("authPriv", optarg) == 0) { + config.snmp_session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV; + } else { + die(STATE_UNKNOWN, "invalid security level: %s", optarg); + } break; case 'U': /* security username */ - secname = optarg; + config.snmp_session.securityName = optarg; + config.snmp_session.securityNameLen = strlen(optarg); break; case 'a': /* auth protocol */ - authproto = optarg; + // SNMPv3: SHA or MD5 + // TODO Test for availability of individual protocols + if (strcasecmp("MD5", optarg) == 0) { + config.snmp_session.securityAuthProto = usmHMACMD5AuthProtocol; + config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmHMACMD5AuthProtocol); + } else if (strcasecmp("SHA", optarg) == 0) { + config.snmp_session.securityAuthProto = usmHMACSHA1AuthProtocol; + config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmHMACSHA1AuthProtocol); + } else if (strcasecmp("SHA224", optarg) == 0) { + config.snmp_session.securityAuthProto = usmHMAC128SHA224AuthProtocol; + config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmHMAC128SHA224AuthProtocol); + } else if (strcasecmp("SHA256", optarg) == 0) { + config.snmp_session.securityAuthProto = usmHMAC192SHA256AuthProtocol; + config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmHMAC192SHA256AuthProtocol); + } else if (strcasecmp("SHA384", optarg) == 0) { + config.snmp_session.securityAuthProto = usmHMAC256SHA384AuthProtocol; + config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmHMAC256SHA384AuthProtocol); + } else if (strcasecmp("SHA512", optarg) == 0) { + config.snmp_session.securityAuthProto = usmHMAC384SHA512AuthProtocol; + config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmHMAC384SHA512AuthProtocol); + } else { + die(STATE_UNKNOWN, "Unknown authentication protocol"); + } break; case 'x': /* priv protocol */ - privproto = optarg; + if (strcasecmp("DES", optarg) == 0) { + config.snmp_session.securityAuthProto = usmDESPrivProtocol; + config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmDESPrivProtocol); + } else if (strcasecmp("AES", optarg) == 0) { + config.snmp_session.securityAuthProto = usmAESPrivProtocol; + config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmAESPrivProtocol); + // } else if (strcasecmp("AES128", optarg)) { + // config.snmp_session.securityAuthProto = usmAES128PrivProtocol; + // config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmAES128PrivProtocol) + // / OID_LENGTH(oid); + } else if (strcasecmp("AES192", optarg) == 0) { + config.snmp_session.securityAuthProto = usmAES192PrivProtocol; + config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmAES192PrivProtocol); + } else if (strcasecmp("AES256", optarg) == 0) { + config.snmp_session.securityAuthProto = usmAES256PrivProtocol; + config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmAES256PrivProtocol); + // } else if (strcasecmp("AES192Cisco", optarg)) { + // config.snmp_session.securityAuthProto = usmAES192CiscoPrivProtocol; + // config.snmp_session.securityAuthProtoLen = + // sizeof(usmAES192CiscoPrivProtocol) / sizeof(oid); } else if + // (strcasecmp("AES256Cisco", optarg)) { config.snmp_session.securityAuthProto = + // usmAES256CiscoPrivProtocol; config.snmp_session.securityAuthProtoLen = + // sizeof(usmAES256CiscoPrivProtocol) / sizeof(oid); } else if + // (strcasecmp("AES192Cisco2", optarg)) { config.snmp_session.securityAuthProto + // = usmAES192Cisco2PrivProtocol; config.snmp_session.securityAuthProtoLen = + // sizeof(usmAES192Cisco2PrivProtocol) / sizeof(oid); } else if + // (strcasecmp("AES256Cisco2", optarg)) { config.snmp_session.securityAuthProto + // = usmAES256Cisco2PrivProtocol; config.snmp_session.securityAuthProtoLen = + // sizeof(usmAES256Cisco2PrivProtocol) / sizeof(oid); + } else { + die(STATE_UNKNOWN, "Unknow privacy protocol"); + } break; case 'A': /* auth passwd */ - authpasswd = optarg; + authpasswd = (unsigned char *)optarg; break; case 'X': /* priv passwd */ - privpasswd = optarg; + privpasswd = (unsigned char *)optarg; + break; + case 'e': + case 'E': + if (!is_integer(optarg)) { + usage2(_("Retries interval must be a positive integer"), optarg); + } else { + config.snmp_session.retries = atoi(optarg); + } break; case 't': /* timeout period */ - if (!is_integer(optarg)) + if (!is_integer(optarg)) { usage2(_("Timeout interval must be a positive integer"), optarg); - else + } else { timeout_interval = atoi(optarg); + } break; /* Test parameters */ case 'c': /* critical threshold */ - critical_thresholds = optarg; - break; + { + mp_range_parsed tmp = mp_parse_range_string(optarg); + if (tmp.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "Unable to parse critical threshold range: %s", optarg); + } + config.thresholds.critical = tmp.range; + config.thresholds.critical_is_set = true; + } break; case 'w': /* warning threshold */ - warning_thresholds = optarg; - break; - case 'e': /* PRELIMINARY - may change */ - case 'E': /* PRELIMINARY - may change */ - if (!is_integer(optarg)) - usage2(_("Retries interval must be a positive integer"), optarg); - else - retries = atoi(optarg); - break; + { + mp_range_parsed tmp = mp_parse_range_string(optarg); + if (tmp.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "Unable to parse warning threshold range: %s", optarg); + } + config.thresholds.warning = tmp.range; + config.thresholds.warning_is_set = true; + } break; case 'o': /* object identifier */ if (strspn(optarg, "0123456789.,") != strlen(optarg)) { /* @@ -824,306 +684,246 @@ int process_arguments(int argc, char **argv) { * so we have a mib variable, rather than just an SNMP OID, * so we have to actually read the mib files */ - needmibs = true; - } - for (char *ptr = strtok(optarg, ", "); ptr != NULL; ptr = strtok(NULL, ", "), j++) { - while (j >= oids_size) { - oids_size += OID_COUNT_STEP; - oids = realloc(oids, oids_size * sizeof(*oids)); - } - oids[j] = strdup(ptr); + config.need_mibs = true; } - numoids = j; - if (option_char == 'E' || option_char == 'e') { - jj++; - while (j + 1 >= eval_size) { - eval_size += OID_COUNT_STEP; - eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); - memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8); - } - if (option_char == 'E') - eval_method[j + 1] |= WARN_PRESENT; - else if (option_char == 'e') - eval_method[j + 1] |= CRIT_PRESENT; + + for (char *ptr = strtok(optarg, ", "); ptr != NULL; + ptr = strtok(NULL, ", "), tmp_oid_counter++) { + config.test_units[tmp_oid_counter].oid = strdup(ptr); } break; case 'z': /* Null OID Return Check */ - if (!is_integer(optarg)) + if (!is_integer(optarg)) { usage2(_("Exit status must be a positive integer"), optarg); - else - nulloid = atoi(optarg); + } else { + config.nulloid_result = atoi(optarg); + } break; case 's': /* string or substring */ - strncpy(string_value, optarg, sizeof(string_value) - 1); - string_value[sizeof(string_value) - 1] = 0; - while (jj >= eval_size) { - eval_size += OID_COUNT_STEP; - eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); - memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8); - } - eval_method[jj++] = CRIT_STRING; + strncpy(config.string_cmp_value, optarg, sizeof(config.string_cmp_value) - 1); + config.string_cmp_value[sizeof(config.string_cmp_value) - 1] = 0; + config.test_units[eval_counter++].eval_mthd.crit_string = true; break; case 'R': /* regex */ cflags = REG_ICASE; // fall through case 'r': /* regex */ + { + char regex_expect[MAX_INPUT_BUFFER] = ""; cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; strncpy(regex_expect, optarg, sizeof(regex_expect) - 1); regex_expect[sizeof(regex_expect) - 1] = 0; - errcode = regcomp(&preg, regex_expect, cflags); + int errcode = regcomp(&config.regex_cmp_value, regex_expect, cflags); if (errcode != 0) { - regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); - printf(_("Could Not Compile Regular Expression")); - return ERROR; + char errbuf[MAX_INPUT_BUFFER] = ""; + regerror(errcode, &config.regex_cmp_value, errbuf, MAX_INPUT_BUFFER); + printf("Could Not Compile Regular Expression: %s", errbuf); + process_arguments_wrapper result = { + .errorcode = ERROR, + }; + return result; } - while (jj >= eval_size) { - eval_size += OID_COUNT_STEP; - eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); - memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8); - } - eval_method[jj++] = CRIT_REGEX; - break; - - /* Format */ - case 'd': /* delimiter */ - delimiter = strscpy(delimiter, optarg); - break; - case 'D': /* output-delimiter */ - output_delim = strscpy(output_delim, optarg); - break; + config.test_units[eval_counter++].eval_mthd.crit_regex = true; + } break; case 'l': /* label */ - nlabels++; - if (nlabels > labels_size) { - labels_size += 8; - labels = realloc(labels, labels_size * sizeof(*labels)); - if (labels == NULL) - die(STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels); + { + if (labels_counter >= config.num_of_test_units) { + break; } - labels[nlabels - 1] = optarg; - char *ptr = thisarg(optarg); - labels[nlabels - 1] = ptr; - if (ptr[0] == '\'') - labels[nlabels - 1] = ptr + 1; - while (ptr && (ptr = nextarg(ptr))) { - nlabels++; - if (nlabels > labels_size) { - labels_size += 8; - labels = realloc(labels, labels_size * sizeof(*labels)); - if (labels == NULL) - die(STATE_UNKNOWN, _("Could not reallocate labels\n")); + char *ptr = trim_whitespaces_and_check_quoting(optarg); + if (ptr[0] == '\'') { + config.test_units[labels_counter].label = ptr + 1; + } else { + config.test_units[labels_counter].label = ptr; + } + + while (ptr && (ptr = get_next_argument(ptr))) { + labels_counter++; + ptr = trim_whitespaces_and_check_quoting(ptr); + if (ptr[0] == '\'') { + config.test_units[labels_counter].label = ptr + 1; + } else { + config.test_units[labels_counter].label = ptr; } - ptr = thisarg(ptr); - if (ptr[0] == '\'') - labels[nlabels - 1] = ptr + 1; - else - labels[nlabels - 1] = ptr; } - break; + labels_counter++; + } break; case 'u': /* units */ - units = optarg; - nunits++; - if (nunits > unitv_size) { - unitv_size += 8; - unitv = realloc(unitv, unitv_size * sizeof(*unitv)); - if (unitv == NULL) - die(STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits); + { + if (unitv_counter >= config.num_of_test_units) { + break; } - unitv[nunits - 1] = optarg; - ptr = thisarg(optarg); - unitv[nunits - 1] = ptr; - if (ptr[0] == '\'') - unitv[nunits - 1] = ptr + 1; - while (ptr && (ptr = nextarg(ptr))) { - if (nunits > unitv_size) { - unitv_size += 8; - unitv = realloc(unitv, unitv_size * sizeof(*unitv)); - if (units == NULL) - die(STATE_UNKNOWN, _("Could not realloc() units\n")); + char *ptr = trim_whitespaces_and_check_quoting(optarg); + if (ptr[0] == '\'') { + config.test_units[unitv_counter].unit_value = ptr + 1; + } else { + config.test_units[unitv_counter].unit_value = ptr; + } + while (ptr && (ptr = get_next_argument(ptr))) { + unitv_counter++; + ptr = trim_whitespaces_and_check_quoting(ptr); + if (ptr[0] == '\'') { + config.test_units[unitv_counter].unit_value = ptr + 1; + } else { + config.test_units[unitv_counter].unit_value = ptr; } - nunits++; - ptr = thisarg(ptr); - if (ptr[0] == '\'') - unitv[nunits - 1] = ptr + 1; - else - unitv[nunits - 1] = ptr; } - break; - case L_CALCULATE_RATE: - if (calculate_rate == 0) - np_enable_state(NULL, 1); - calculate_rate = 1; - break; - case L_RATE_MULTIPLIER: - if (!is_integer(optarg) || ((rate_multiplier = atoi(optarg)) <= 0)) - usage2(_("Rate multiplier must be a positive integer"), optarg); - break; + unitv_counter++; + } break; case L_OFFSET: - offset = strtod(optarg, NULL); + config.offset = strtod(optarg, NULL); break; case L_INVERT_SEARCH: - invert_search = 1; + config.invert_search = false; break; case 'O': - perf_labels = 0; + config.use_perf_data_labels_from_input = true; break; case '4': + // The default, do something here to be exclusive to -6 instead of doing nothing? + connection_prefix = "udp"; break; case '6': - xasprintf(&ip_version, "udp6:"); - if (verbose > 2) - printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n"); + connection_prefix = "udp6"; + break; + case L_CONNECTION_PREFIX: + connection_prefix = optarg; break; case 'M': if (strspn(optarg, "0123456789.,") == strlen(optarg)) { - multiplier = strtod(optarg, NULL); - } - break; - case 'f': - if (multiplier != 1.0) { - fmtstr = optarg; - fmtstr_set = true; + config.multiplier = strtod(optarg, NULL); } break; case L_IGNORE_MIB_PARSING_ERRORS: - ignore_mib_parsing_errors = true; + config.ignore_mib_parsing_errors = true; } } - if (server_address == NULL) - server_address = argv[optind]; - - if (community == NULL) - community = strdup(DEFAULT_COMMUNITY); - - return validate_arguments(); -} - -/****************************************************************************** - -@@- - -validate_arguments - -&PROTO_validate_arguments; - -Checks to see if the default miblist needs to be loaded. Also verifies -the authentication and authorization combinations based on protocol version -selected. - - - - --@@ -******************************************************************************/ + if (config.snmp_session.peername == NULL) { + config.snmp_session.peername = argv[optind]; + } -static int validate_arguments() { - /* check whether to load locally installed MIBS (CPU/disk intensive) */ - if (miblist == NULL) { - if (needmibs) { - miblist = strdup(DEFAULT_MIBLIST); + // Build true peername here if necessary + if (connection_prefix != NULL) { + // We got something in the connection prefix + if (strcasecmp(connection_prefix, "udp") == 0) { + // The default, do nothing + } else if (strcasecmp(connection_prefix, "tcp") == 0) { + // use tcp/ipv4 + xasprintf(&config.snmp_session.peername, "tcp:%s", config.snmp_session.peername); + } else if (strcasecmp(connection_prefix, "tcp6") == 0 || + strcasecmp(connection_prefix, "tcpv6") == 0 || + strcasecmp(connection_prefix, "tcpipv6") == 0 || + strcasecmp(connection_prefix, "udp6") == 0 || + strcasecmp(connection_prefix, "udpipv6") == 0 || + strcasecmp(connection_prefix, "udpv6") == 0) { + // Man page (or net-snmp) code says IPv6 addresses should be wrapped in [], but it + // works anyway therefore do nothing here + xasprintf(&config.snmp_session.peername, "%s:%s", connection_prefix, + config.snmp_session.peername); + } else if (strcmp(connection_prefix, "tls") == 0) { + // TODO: Anything else to do here? + xasprintf(&config.snmp_session.peername, "tls:%s", config.snmp_session.peername); + } else if (strcmp(connection_prefix, "dtls") == 0) { + // TODO: Anything else to do here? + xasprintf(&config.snmp_session.peername, "dtls:%s", config.snmp_session.peername); + } else if (strcmp(connection_prefix, "unix") == 0) { + // TODO: Check whether this is a valid path? + xasprintf(&config.snmp_session.peername, "unix:%s", config.snmp_session.peername); + } else if (strcmp(connection_prefix, "ipx") == 0) { + xasprintf(&config.snmp_session.peername, "ipx:%s", config.snmp_session.peername); } else { - miblist = ""; /* don't read any mib files for numeric oids */ + // Don't know that prefix, die here + die(STATE_UNKNOWN, "Unknown connection prefix"); } } /* Check server_address is given */ - if (server_address == NULL) + if (config.snmp_session.peername == NULL) { die(STATE_UNKNOWN, _("No host specified\n")); + } - /* Check oid is given */ - if (numoids == 0) - die(STATE_UNKNOWN, _("No OIDs specified\n")); + if (port != NULL) { + xasprintf(&config.snmp_session.peername, "%s:%s", config.snmp_session.peername, port); + } - if (proto == NULL) - xasprintf(&proto, DEFAULT_PROTOCOL); - - if ((strcmp(proto, "1") == 0) || (strcmp(proto, "2c") == 0)) { /* snmpv1 or snmpv2c */ - numauthpriv = 2; - authpriv = calloc(numauthpriv, sizeof(char *)); - authpriv[0] = strdup("-c"); - authpriv[1] = strdup(community); - } else if (strcmp(proto, "3") == 0) { /* snmpv3 args */ - if (!(context == NULL)) { - numcontext = 2; - contextargs = calloc(numcontext, sizeof(char *)); - contextargs[0] = strdup("-n"); - contextargs[1] = strdup(context); + /* check whether to load locally installed MIBS (CPU/disk intensive) */ + if (miblist == NULL) { + if (config.need_mibs) { + setenv("MIBLS", DEFAULT_MIBLIST, 1); + } else { + setenv("MIBLS", "NONE", 1); + miblist = ""; /* don't read any mib files for numeric oids */ } + } else { + // Blatantly stolen from snmplib/snmp_parse_args + setenv("MIBS", miblist, 1); + } - if (seclevel == NULL) - xasprintf(&seclevel, "noAuthNoPriv"); - - if (secname == NULL) + if ((config.snmp_session.version == SNMP_VERSION_1) || + (config.snmp_session.version == SNMP_VERSION_2c)) { /* snmpv1 or snmpv2c */ + /* + config.numauthpriv = 2; + config.authpriv = calloc(config.numauthpriv, sizeof(char *)); + config.authpriv[0] = strdup("-c"); + config.authpriv[1] = strdup(community); + */ + } else if (config.snmp_session.version == SNMP_VERSION_3) { /* snmpv3 args */ + // generate keys for priv and auth here (if demanded) + + if (config.snmp_session.securityName == NULL) { die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname"); + } - if (strcmp(seclevel, "noAuthNoPriv") == 0) { - numauthpriv = 4; - authpriv = calloc(numauthpriv, sizeof(char *)); - authpriv[0] = strdup("-l"); - authpriv[1] = strdup("noAuthNoPriv"); - authpriv[2] = strdup("-u"); - authpriv[3] = strdup(secname); - } else { - if (!((strcmp(seclevel, "authNoPriv") == 0) || (strcmp(seclevel, "authPriv") == 0))) { - usage2(_("Invalid seclevel"), seclevel); + switch (config.snmp_session.securityLevel) { + case SNMP_SEC_LEVEL_AUTHPRIV: { + if (authpasswd == NULL) { + die(STATE_UNKNOWN, + "No authentication passphrase was given, but authorization was requested"); } - - if (authproto == NULL) - xasprintf(&authproto, DEFAULT_AUTH_PROTOCOL); - - if (authpasswd == NULL) - die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd"); - - if (strcmp(seclevel, "authNoPriv") == 0) { - numauthpriv = 8; - authpriv = calloc(numauthpriv, sizeof(char *)); - authpriv[0] = strdup("-l"); - authpriv[1] = strdup("authNoPriv"); - authpriv[2] = strdup("-a"); - authpriv[3] = strdup(authproto); - authpriv[4] = strdup("-u"); - authpriv[5] = strdup(secname); - authpriv[6] = strdup("-A"); - authpriv[7] = strdup(authpasswd); - } else if (strcmp(seclevel, "authPriv") == 0) { - if (privproto == NULL) - xasprintf(&privproto, DEFAULT_PRIV_PROTOCOL); - - if (privpasswd == NULL) - die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd"); - - numauthpriv = 12; - authpriv = calloc(numauthpriv, sizeof(char *)); - authpriv[0] = strdup("-l"); - authpriv[1] = strdup("authPriv"); - authpriv[2] = strdup("-a"); - authpriv[3] = strdup(authproto); - authpriv[4] = strdup("-u"); - authpriv[5] = strdup(secname); - authpriv[6] = strdup("-A"); - authpriv[7] = strdup(authpasswd); - authpriv[8] = strdup("-x"); - authpriv[9] = strdup(privproto); - authpriv[10] = strdup("-X"); - authpriv[11] = strdup(privpasswd); + // auth and priv + size_t priv_key_generated = generate_Ku( + config.snmp_session.securityPrivProto, config.snmp_session.securityPrivProtoLen, + authpasswd, strlen((const char *)authpasswd), config.snmp_session.securityPrivKey, + &config.snmp_session.securityPrivKeyLen); + if (priv_key_generated != SNMPERR_SUCCESS) { + die(STATE_UNKNOWN, "Failed to generate privacy key"); } } - - } else { - usage2(_("Invalid SNMP version"), proto); + // fall through + case SNMP_SEC_LEVEL_AUTHNOPRIV: { + if (privpasswd == NULL) { + die(STATE_UNKNOWN, "No privacy passphrase was given, but privacy was requested"); + } + size_t auth_key_generated = generate_Ku( + config.snmp_session.securityAuthProto, config.snmp_session.securityAuthProtoLen, + privpasswd, strlen((const char *)privpasswd), config.snmp_session.securityAuthKey, + &config.snmp_session.securityAuthKeyLen); + if (auth_key_generated != SNMPERR_SUCCESS) { + die(STATE_UNKNOWN, "Failed to generate privacy key"); + } + } break; + case SNMP_SEC_LEVEL_NOAUTH: + // No auth, no priv, not much todo + break; + } } - return OK; + process_arguments_wrapper result = { + .config = config, + .errorcode = OK, + }; + return result; } /* trim leading whitespace if there is a leading quote, make sure it balances */ - -static char *thisarg(char *str) { +char *trim_whitespaces_and_check_quoting(char *str) { str += strspn(str, " \t\r\n"); /* trim any leading whitespace */ if (str[0] == '\'') { /* handle SIMPLE quoted strings */ - if (strlen(str) == 1 || !strstr(str + 1, "'")) + if (strlen(str) == 1 || !strstr(str + 1, "'")) { die(STATE_UNKNOWN, _("Unbalanced quotes\n")); + } } return str; } @@ -1132,23 +932,21 @@ static char *thisarg(char *str) { set the trailing quote to '\x0' if the string continues, advance beyond the comma */ -static char *nextarg(char *str) { +char *get_next_argument(char *str) { if (str[0] == '\'') { str[0] = 0; if (strlen(str) > 1) { str = strstr(str + 1, "'"); return (++str); - } else { - return NULL; } + return NULL; } if (str[0] == ',') { str[0] = 0; if (strlen(str) > 1) { return (++str); - } else { - return NULL; } + return NULL; } if ((str = strstr(str, ",")) && strlen(str) > 1) { str[0] = 0; @@ -1158,40 +956,53 @@ static char *nextarg(char *str) { } /* multiply result (values 0 < n < 1 work as divider) */ -static char *multiply(char *str) { - if (multiplier == 1) +char *multiply(char *str, double multiplier, char *fmt_str) { + + if (multiplier == 1) { return (str); + } - if (verbose > 2) + if (verbose > 2) { printf(" multiply input: %s\n", str); + } char *endptr; double val = strtod(str, &endptr); if ((val == 0.0) && (endptr == str)) { - die(STATE_UNKNOWN, _("multiplier set (%.1f), but input is not a number: %s"), multiplier, str); + die(STATE_UNKNOWN, _("multiplier set (%.1f), but input is not a number: %s"), multiplier, + str); } - if (verbose > 2) + if (verbose > 2) { printf(" multiply extracted double: %f\n", val); + } val *= multiplier; char *conv = "%f"; - if (fmtstr_set) { - conv = fmtstr; + if (fmt_str != NULL) { + conv = fmt_str; } + + char *buffer = calloc(1, DEFAULT_BUFFER_SIZE); + if (buffer == NULL) { + die(STATE_UNKNOWN, "calloc failed"); + } + if (val == (int)val) { snprintf(buffer, DEFAULT_BUFFER_SIZE, "%.0f", val); } else { - if (verbose > 2) + if (verbose > 2) { printf(" multiply using format: %s\n", conv); + } snprintf(buffer, DEFAULT_BUFFER_SIZE, conv, val); } - if (verbose > 2) + if (verbose > 2) { printf(" multiply result: %s\n", buffer); + } return buffer; } -static void print_help(void) { +void print_help(void) { print_revision(progname, NP_VERSION); printf(COPYRIGHT, copyright, email); @@ -1204,8 +1015,6 @@ static void print_help(void) { printf(UT_HELP_VRSN); printf(UT_EXTRA_OPTS); - printf(UT_IPv46); - printf(UT_HOST_PORT, 'p', DEFAULT_PORT); /* SNMP and Authentication Protocol */ @@ -1217,13 +1026,10 @@ static void print_help(void) { printf(" %s\n", _("SNMPv3 context")); printf(" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]"); printf(" %s\n", _("SNMPv3 securityLevel")); - printf(" %s\n", "-a, --authproto=AUTHENTICATION_PROTOCOL"); - printf(" %s\n", - _("SNMPv3 authentication protocol (default MD5), available options depend on the specific version of the net-snmp tools")); - 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")); - printf(" %s\n", "-x, --privproto=PRIVACY_PROTOCOL"); - printf(" %s\n", _("SNMPv3 privacy protocol (default DES), available options depend on the specific version of the net-snmp tools")); - printf(" %s\n", _("if < 5.8 DES and AES should be available, if >= 5.8 additionally AES-192 and AES-256")); + printf(" %s\n", "-a, --authproto=[MD5|SHA]"); + printf(" %s\n", _("SNMPv3 auth proto")); + printf(" %s\n", "-x, --privproto=[DES|AES]"); + printf(" %s\n", _("SNMPv3 priv proto (default DES)")); /* Authentication Tokens*/ printf(" %s\n", "-C, --community=STRING"); @@ -1235,15 +1041,21 @@ static void print_help(void) { printf(" %s\n", _("SNMPv3 authentication password")); printf(" %s\n", "-X, --privpasswd=PASSWORD"); printf(" %s\n", _("SNMPv3 privacy password")); + printf(" %s\n", "--connection-prefix"); + printf(" Connection prefix, may be one of udp, udp6, tcp, unix, ipx, udp6, udpv6, udpipv6, " + "tcp6, tcpv6, tcpipv6, tls, dtls - " + "default is \"udp\"\n"); /* OID Stuff */ printf(" %s\n", "-o, --oid=OID(s)"); printf(" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query")); printf(" %s\n", "-m, --miblist=STRING"); - printf(" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'")); + printf(" %s\n", + _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'")); printf(" %s\n", _("for symbolic OIDs.)")); printf(" %s\n", "-d, --delimiter=STRING"); - printf(" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER); + printf(" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), + DEFAULT_DELIMITER); printf(" %s\n", _("Any data on the right hand side of the delimiter is considered")); printf(" %s\n", _("to be the data that should be used in the evaluation.")); printf(" %s\n", "-z, --nulloid=#"); @@ -1260,10 +1072,6 @@ static void print_help(void) { printf(" %s\n", _("Warning threshold range(s)")); printf(" %s\n", "-c, --critical=THRESHOLD(s)"); printf(" %s\n", _("Critical threshold range(s)")); - printf(" %s\n", "--rate"); - printf(" %s\n", _("Enable rate calculation. See 'Rate Calculation' below")); - printf(" %s\n", "--rate-multiplier"); - printf(" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute")); printf(" %s\n", "--offset=OFFSET"); printf(" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data")); @@ -1271,9 +1079,11 @@ static void print_help(void) { printf(" %s\n", "-s, --string=STRING"); printf(" %s\n", _("Return OK state (for that OID) if STRING is an exact match")); printf(" %s\n", "-r, --ereg=REGEX"); - printf(" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches")); + printf(" %s\n", + _("Return OK state (for that OID) if extended regular expression REGEX matches")); printf(" %s\n", "-R, --eregi=REGEX"); - printf(" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches")); + printf(" %s\n", + _("Return OK state (for that OID) if case-insensitive extended REGEX matches")); printf(" %s\n", "--invert-search"); printf(" %s\n", _("Invert search result (CRITICAL if found)")); @@ -1282,53 +1092,45 @@ static void print_help(void) { printf(" %s\n", _("Prefix label for output from plugin")); printf(" %s\n", "-u, --units=STRING"); printf(" %s\n", _("Units label(s) for output data (e.g., 'sec.').")); - printf(" %s\n", "-D, --output-delimiter=STRING"); - printf(" %s\n", _("Separates output on multiple OID requests")); printf(" %s\n", "-M, --multiplier=FLOAT"); printf(" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1")); - printf(" %s\n", "-f, --fmtstr=STRING"); - printf(" %s\n", _("C-style format string for float values (see option -M)")); printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); - printf(" %s\n", _("NOTE the final timeout value is calculated using this formula: timeout_interval * retries + 5")); + printf(" %s\n", _("NOTE the final timeout value is calculated using this formula: " + "timeout_interval * retries + 5")); printf(" %s\n", "-e, --retries=INTEGER"); - printf(" %s%i\n", _("Number of retries to be used in the requests, default: "), DEFAULT_RETRIES); + printf(" %s%i\n", _("Number of retries to be used in the requests, default: "), + DEFAULT_RETRIES); printf(" %s\n", "-O, --perf-oids"); printf(" %s\n", _("Label performance data with OIDs instead of --label's")); printf(" %s\n", "--ignore-mib-parsing-errors"); - printf(" %s\n", _("Tell snmpget to not print errors encountered when parsing MIB files")); + printf(" %s\n", _("Do to not print errors encountered when parsing MIB files")); printf(UT_VERBOSE); printf("\n"); - printf("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package.")); - printf("%s\n", _("if you don't have the package installed, you will need to download it from")); + printf("%s\n", _("This plugin relies (links against) on the NET-SNMP libraries.")); + printf("%s\n", + _("if you don't have the libraries installed, you will need to download them from")); printf("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin.")); printf("\n"); printf("%s\n", _("Notes:")); - printf(" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited ")); + printf(" %s\n", + _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited ")); printf(" %s\n", _("list (lists with internal spaces must be quoted).")); printf(" -%s", UT_THRESHOLDS_NOTES); - printf(" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'")); + printf(" %s\n", + _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'")); printf(" %s\n", _("- Note that only one string and one regex may be checked at present")); - printf(" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value")); + printf(" %s\n", + _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value")); printf(" %s\n", _("returned from the SNMP query is an unsigned integer.")); - printf("\n"); - printf("%s\n", _("Rate Calculation:")); - printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when")); - printf(" %s\n", _("calculating the counter difference since the last check. check_snmp")); - printf(" %s\n", _("saves the last state information in a file so that the rate per second")); - printf(" %s\n", _("can be calculated. Use the --rate option to save state information.")); - printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK.")); - printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so")); - printf(" %s\n", _("changing the arguments will create a new state file.")); - printf(UT_SUPPORT); } -- cgit v1.2.3-74-g34f1