From 65794e31374b3aa6e1f2c03d090b52e137df13e6 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sat, 8 Mar 2025 13:05:57 +0100 Subject: Refactor check_dns --- plugins/check_dns.c | 240 ++++++++++++++++++++++--------------------- plugins/check_dns.d/config.h | 34 ++++++ 2 files changed, 158 insertions(+), 116 deletions(-) create mode 100644 plugins/check_dns.d/config.h (limited to 'plugins') diff --git a/plugins/check_dns.c b/plugins/check_dns.c index b3d4a6e5..7071c01f 100644 --- a/plugins/check_dns.c +++ b/plugins/check_dns.c @@ -39,26 +39,22 @@ const char *email = "devel@monitoring-plugins.org"; #include "netutils.h" #include "runcmd.h" -static int process_arguments(int /*argc*/, char ** /*argv*/); -static int validate_arguments(void); -static int error_scan(char * /*input_buffer*/, bool *); +#include "states.h" +#include "check_dns.d/config.h" + +typedef struct { + int errorcode; + check_dns_config config; +} check_dns_config_wrapper; +static check_dns_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); +static check_dns_config_wrapper validate_arguments(check_dns_config_wrapper /*config_wrapper*/); +static mp_state_enum error_scan(char * /*input_buffer*/, bool * /*is_nxdomain*/, const char /*dns_server*/[ADDRESS_LENGTH]); static bool ip_match_cidr(const char * /*addr*/, const char * /*cidr_ro*/); static unsigned long ip2long(const char * /*src*/); static void print_help(void); void print_usage(void); -#define ADDRESS_LENGTH 256 -static char query_address[ADDRESS_LENGTH] = ""; -static char dns_server[ADDRESS_LENGTH] = ""; -static char ptr_server[ADDRESS_LENGTH] = ""; static bool verbose = false; -static char **expected_address = NULL; -static int expected_address_cnt = 0; -static bool expect_nxdomain = false; - -static bool expect_authority = false; -static bool all_match = false; -static thresholds *time_thresholds = NULL; static int qstrcmp(const void *p1, const void *p2) { /* The actual arguments to this function are "pointers to @@ -68,23 +64,6 @@ static int qstrcmp(const void *p1, const void *p2) { } int main(int argc, char **argv) { - char *command_line = NULL; - char input_buffer[MAX_INPUT_BUFFER]; - char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */ - char **addresses = NULL; - int n_addresses = 0; - char *msg = NULL; - char *temp_buffer = NULL; - bool non_authoritative = false; - int result = STATE_UNKNOWN; - double elapsed_time; - long microsec; - struct timeval tv; - bool parse_address = false; /* This flag scans for Address: but only after Name: */ - output chld_out; - output chld_err; - bool is_nxdomain = false; - setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); @@ -97,13 +76,19 @@ int main(int argc, char **argv) { /* Parse extra opts if any */ argv = np_extra_opts(&argc, argv, progname); - if (process_arguments(argc, argv) == ERROR) { + check_dns_config_wrapper tmp = process_arguments(argc, argv); + + if (tmp.errorcode == ERROR) { usage_va(_("Could not parse arguments")); } + const check_dns_config config = tmp.config; + + char *command_line = NULL; /* get the command to run */ - xasprintf(&command_line, "%s %s %s", NSLOOKUP_COMMAND, query_address, dns_server); + xasprintf(&command_line, "%s %s %s", NSLOOKUP_COMMAND, config.query_address, config.dns_server); + struct timeval tv; alarm(timeout_interval); gettimeofday(&tv, NULL); @@ -111,12 +96,23 @@ int main(int argc, char **argv) { printf("%s\n", command_line); } + output chld_out; + output chld_err; + char *msg = NULL; + mp_state_enum result = STATE_UNKNOWN; /* run the command */ if ((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) { msg = (char *)_("nslookup returned an error status"); result = STATE_WARNING; } + char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */ + char **addresses = NULL; + size_t n_addresses = 0; + bool non_authoritative = false; + bool is_nxdomain = false; + char *temp_buffer = NULL; + bool parse_address = false; /* This flag scans for Address: but only after Name: */ /* scan stdout */ for (size_t i = 0; i < chld_out.lines; i++) { if (addresses == NULL) { @@ -140,21 +136,22 @@ int main(int argc, char **argv) { /* bug ID: 2946553 - Older versions of bind will use all available dns servers, we have to match the one specified */ - if (strstr(chld_out.line[i], "Server:") && strlen(dns_server) > 0) { + if (strstr(chld_out.line[i], "Server:") && strlen(config.dns_server) > 0) { temp_buffer = strchr(chld_out.line[i], ':'); temp_buffer++; /* Strip leading tabs */ - for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++) + for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++) { /* NOOP */; + } strip(temp_buffer); if (temp_buffer == NULL || strlen(temp_buffer) == 0) { die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty server string\n"), NSLOOKUP_COMMAND); } - if (strcmp(temp_buffer, dns_server) != 0) { - die(STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), dns_server); + if (strcmp(temp_buffer, config.dns_server) != 0) { + die(STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), config.dns_server); } } @@ -180,7 +177,7 @@ int main(int argc, char **argv) { non_authoritative = true; } - result = error_scan(chld_out.line[i], &is_nxdomain); + result = error_scan(chld_out.line[i], &is_nxdomain, config.dns_server); if (result != STATE_OK) { msg = strchr(chld_out.line[i], ':'); if (msg) { @@ -190,14 +187,15 @@ int main(int argc, char **argv) { } } + char input_buffer[MAX_INPUT_BUFFER]; /* scan stderr */ for (size_t i = 0; i < chld_err.lines; i++) { if (verbose) { puts(chld_err.line[i]); } - if (error_scan(chld_err.line[i], &is_nxdomain) != STATE_OK) { - result = max_state(result, error_scan(chld_err.line[i], &is_nxdomain)); + if (error_scan(chld_err.line[i], &is_nxdomain, config.dns_server) != STATE_OK) { + result = max_state(result, error_scan(chld_err.line[i], &is_nxdomain, config.dns_server)); msg = strchr(input_buffer, ':'); if (msg) { msg++; @@ -207,20 +205,19 @@ int main(int argc, char **argv) { } } - if (is_nxdomain && !expect_nxdomain) { - die(STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), query_address); + if (is_nxdomain && !config.expect_nxdomain) { + die(STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), config.query_address); } if (addresses) { - int i; - int slen; - char *adrp; + size_t slen = 1; + char *adrp = NULL; qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp); - for (i = 0, slen = 1; i < n_addresses; i++) { + for (size_t i = 0; i < n_addresses; i++) { slen += strlen(addresses[i]) + 1; } adrp = address = malloc(slen); - for (i = 0; i < n_addresses; i++) { + for (size_t i = 0; i < n_addresses; i++) { if (i) { *adrp++ = ','; } @@ -233,17 +230,16 @@ int main(int argc, char **argv) { } /* compare to expected address */ - if (result == STATE_OK && expected_address_cnt > 0) { + if (result == STATE_OK && config.expected_address_cnt > 0) { result = STATE_CRITICAL; temp_buffer = ""; - unsigned long expect_match = (1 << expected_address_cnt) - 1; + unsigned long expect_match = (1 << config.expected_address_cnt) - 1; unsigned long addr_match = (1 << n_addresses) - 1; - for (int i = 0; i < expected_address_cnt; i++) { - int j; + for (size_t i = 0; i < config.expected_address_cnt; i++) { /* check if we get a match on 'raw' ip or cidr */ - for (j = 0; j < n_addresses; j++) { - if (strcmp(addresses[j], expected_address[i]) == 0 || ip_match_cidr(addresses[j], expected_address[i])) { + for (size_t j = 0; j < n_addresses; j++) { + if (strcmp(addresses[j], config.expected_address[i]) == 0 || ip_match_cidr(addresses[j], config.expected_address[i])) { result = STATE_OK; addr_match &= ~(1 << j); expect_match &= ~(1 << i); @@ -251,10 +247,10 @@ int main(int argc, char **argv) { } /* prepare an error string */ - xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]); + xasprintf(&temp_buffer, "%s%s; ", temp_buffer, config.expected_address[i]); } /* check if expected_address must cover all in addresses and none may be missing */ - if (all_match && (expect_match != 0 || addr_match != 0)) { + if (config.all_match && (expect_match != 0 || addr_match != 0)) { result = STATE_CRITICAL; } if (result == STATE_CRITICAL) { @@ -264,10 +260,10 @@ int main(int argc, char **argv) { } } - if (expect_nxdomain) { + if (config.expect_nxdomain) { if (!is_nxdomain) { result = STATE_CRITICAL; - xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), query_address, address); + xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), config.query_address, address); } else { if (address != NULL) { free(address); @@ -277,16 +273,16 @@ int main(int argc, char **argv) { } /* check if authoritative */ - if (result == STATE_OK && expect_authority && non_authoritative) { + if (result == STATE_OK && config.expect_authority && non_authoritative) { result = STATE_CRITICAL; - xasprintf(&msg, _("server %s is not authoritative for %s"), dns_server, query_address); + xasprintf(&msg, _("server %s is not authoritative for %s"), config.dns_server, config.query_address); } - microsec = deltime(tv); - elapsed_time = (double)microsec / 1.0e6; + long microsec = deltime(tv); + double elapsed_time = (double)microsec / 1.0e6; if (result == STATE_OK) { - result = get_status(elapsed_time, time_thresholds); + result = get_status(elapsed_time, config.time_thresholds); if (result == STATE_OK) { printf("DNS %s: ", _("OK")); } else if (result == STATE_WARNING) { @@ -295,14 +291,14 @@ int main(int argc, char **argv) { printf("DNS %s: ", _("CRITICAL")); } printf(ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time); - printf(_(". %s returns %s"), query_address, address); - if ((time_thresholds->warning != NULL) && (time_thresholds->critical != NULL)) { - printf("|%s\n", fperfdata("time", elapsed_time, "s", true, time_thresholds->warning->end, true, time_thresholds->critical->end, - true, 0, false, 0)); - } else if ((time_thresholds->warning == NULL) && (time_thresholds->critical != NULL)) { - printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, true, time_thresholds->critical->end, true, 0, false, 0)); - } else if ((time_thresholds->warning != NULL) && (time_thresholds->critical == NULL)) { - printf("|%s\n", fperfdata("time", elapsed_time, "s", true, time_thresholds->warning->end, false, 0, true, 0, false, 0)); + printf(_(". %s returns %s"), config.query_address, address); + if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical != NULL)) { + printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, true, + config.time_thresholds->critical->end, true, 0, false, 0)); + } else if ((config.time_thresholds->warning == NULL) && (config.time_thresholds->critical != NULL)) { + printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, true, config.time_thresholds->critical->end, true, 0, false, 0)); + } else if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical == NULL)) { + printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, false, 0, true, 0, false, 0)); } else { printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0)); } @@ -314,7 +310,7 @@ int main(int argc, char **argv) { printf(_("DNS UNKNOWN - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg); } - return result; + exit(result); } bool ip_match_cidr(const char *addr, const char *cidr_ro) { @@ -342,7 +338,7 @@ unsigned long ip2long(const char *src) { : 0; } -int error_scan(char *input_buffer, bool *is_nxdomain) { +mp_state_enum error_scan(char *input_buffer, bool *is_nxdomain, const char dns_server[ADDRESS_LENGTH]) { const int nxdomain = strstr(input_buffer, "Non-existent") || strstr(input_buffer, "** server can't find") || strstr(input_buffer, "** Can't find") || strstr(input_buffer, "NXDOMAIN"); @@ -404,12 +400,7 @@ int error_scan(char *input_buffer, bool *is_nxdomain) { } /* process command-line arguments */ -int process_arguments(int argc, char **argv) { - int c; - char *warning = NULL; - char *critical = NULL; - - int opt_index = 0; +check_dns_config_wrapper process_arguments(int argc, char **argv) { static struct option long_opts[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, @@ -425,24 +416,34 @@ int process_arguments(int argc, char **argv) { {"critical", required_argument, 0, 'c'}, {0, 0, 0, 0}}; + check_dns_config_wrapper result = { + .config = check_dns_config_init(), + .errorcode = OK, + }; + if (argc < 2) { - return ERROR; + result.errorcode = ERROR; + return result; } - for (c = 1; c < argc; c++) { - if (strcmp("-to", argv[c]) == 0) { - strcpy(argv[c], "-t"); + for (int index = 1; index < argc; index++) { + if (strcmp("-to", argv[index]) == 0) { + strcpy(argv[index], "-t"); } } - while (1) { - c = getopt_long(argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index); + char *warning = NULL; + char *critical = NULL; + int opt_index = 0; + int index = 0; + while (true) { + index = getopt_long(argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index); - if (c == -1 || c == EOF) { + if (index == -1 || index == EOF) { break; } - switch (c) { + switch (index) { case 'h': /* help */ print_help(); exit(STATE_UNKNOWN); @@ -459,7 +460,7 @@ int process_arguments(int argc, char **argv) { if (strlen(optarg) >= ADDRESS_LENGTH) { die(STATE_UNKNOWN, _("Input buffer overflow\n")); } - strcpy(query_address, optarg); + strcpy(result.config.query_address, optarg); break; case 's': /* server name */ /* TODO: this host_or_die check is probably unnecessary. @@ -468,14 +469,16 @@ int process_arguments(int argc, char **argv) { if (strlen(optarg) >= ADDRESS_LENGTH) { die(STATE_UNKNOWN, _("Input buffer overflow\n")); } - strcpy(dns_server, optarg); + strcpy(result.config.dns_server, optarg); break; case 'r': /* reverse server name */ /* TODO: Is this host_or_die necessary? */ + // TODO This does not do anything!!! 2025-03-08 rincewind host_or_die(optarg); if (strlen(optarg) >= ADDRESS_LENGTH) { die(STATE_UNKNOWN, _("Input buffer overflow\n")); } + static char ptr_server[ADDRESS_LENGTH] = ""; strcpy(ptr_server, optarg); break; case 'a': /* expected address */ @@ -485,29 +488,32 @@ int process_arguments(int argc, char **argv) { if (strchr(optarg, ',') != NULL) { char *comma = strchr(optarg, ','); while (comma != NULL) { - expected_address = (char **)realloc(expected_address, (expected_address_cnt + 1) * sizeof(char **)); - expected_address[expected_address_cnt] = strndup(optarg, comma - optarg); - expected_address_cnt++; + result.config.expected_address = + (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **)); + result.config.expected_address[result.config.expected_address_cnt] = strndup(optarg, comma - optarg); + result.config.expected_address_cnt++; optarg = comma + 1; comma = strchr(optarg, ','); } - expected_address = (char **)realloc(expected_address, (expected_address_cnt + 1) * sizeof(char **)); - expected_address[expected_address_cnt] = strdup(optarg); - expected_address_cnt++; + result.config.expected_address = + (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **)); + result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg); + result.config.expected_address_cnt++; } else { - expected_address = (char **)realloc(expected_address, (expected_address_cnt + 1) * sizeof(char **)); - expected_address[expected_address_cnt] = strdup(optarg); - expected_address_cnt++; + result.config.expected_address = + (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **)); + result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg); + result.config.expected_address_cnt++; } break; case 'n': /* expect NXDOMAIN */ - expect_nxdomain = true; + result.config.expect_nxdomain = true; break; case 'A': /* expect authority */ - expect_authority = true; + result.config.expect_authority = true; break; case 'L': /* all must match */ - all_match = true; + result.config.all_match = true; break; case 'w': warning = optarg; @@ -520,40 +526,42 @@ int process_arguments(int argc, char **argv) { } } - c = optind; - if (strlen(query_address) == 0 && c < argc) { - if (strlen(argv[c]) >= ADDRESS_LENGTH) { + index = optind; + if (strlen(result.config.query_address) == 0 && index < argc) { + if (strlen(argv[index]) >= ADDRESS_LENGTH) { die(STATE_UNKNOWN, _("Input buffer overflow\n")); } - strcpy(query_address, argv[c++]); + strcpy(result.config.query_address, argv[index++]); } - if (strlen(dns_server) == 0 && c < argc) { + if (strlen(result.config.dns_server) == 0 && index < argc) { /* TODO: See -s option */ - host_or_die(argv[c]); - if (strlen(argv[c]) >= ADDRESS_LENGTH) { + host_or_die(argv[index]); + if (strlen(argv[index]) >= ADDRESS_LENGTH) { die(STATE_UNKNOWN, _("Input buffer overflow\n")); } - strcpy(dns_server, argv[c++]); + strcpy(result.config.dns_server, argv[index++]); } - set_thresholds(&time_thresholds, warning, critical); + set_thresholds(&result.config.time_thresholds, warning, critical); - return validate_arguments(); + return validate_arguments(result); } -int validate_arguments(void) { - if (query_address[0] == 0) { +check_dns_config_wrapper validate_arguments(check_dns_config_wrapper config_wrapper) { + if (config_wrapper.config.query_address[0] == 0) { printf("missing --host argument\n"); - return ERROR; + config_wrapper.errorcode = ERROR; + return config_wrapper; } - if (expected_address_cnt > 0 && expect_nxdomain) { + if (config_wrapper.config.expected_address_cnt > 0 && config_wrapper.config.expect_nxdomain) { printf("--expected-address and --expect-nxdomain cannot be combined\n"); - return ERROR; + config_wrapper.errorcode = ERROR; + return config_wrapper; } - return OK; + return config_wrapper; } void print_help(void) { diff --git a/plugins/check_dns.d/config.h b/plugins/check_dns.d/config.h new file mode 100644 index 00000000..9ec4eb82 --- /dev/null +++ b/plugins/check_dns.d/config.h @@ -0,0 +1,34 @@ +#pragma once + +#include "../../config.h" +#include "thresholds.h" +#include + +#define ADDRESS_LENGTH 256 + +typedef struct { + bool all_match; + char dns_server[ADDRESS_LENGTH]; + char query_address[ADDRESS_LENGTH]; + bool expect_nxdomain; + bool expect_authority; + char **expected_address; + size_t expected_address_cnt; + + thresholds *time_thresholds; +} check_dns_config; + +check_dns_config check_dns_config_init() { + check_dns_config tmp = { + .all_match = false, + .dns_server = "", + .query_address = "", + .expect_nxdomain = false, + .expect_authority = false, + .expected_address = NULL, + .expected_address_cnt = 0, + + .time_thresholds = NULL, + }; + return tmp; +} -- cgit v1.2.3-74-g34f1