summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDennis Ullrich <dennis.ullrich@plusserver.com>2025-10-07 14:33:55 +0200
committerDennis Ullrich <dennis.ullrich@plusserver.com>2025-10-07 14:34:50 +0200
commit978343ed03d3327597fa3317901f1c1741a7e3c4 (patch)
treef4ba9e7f2a4c2c2bfecf2f884b8ef2884bebd828
parentce10a6ff37119348503086686971eba1190a90a5 (diff)
downloadmonitoring-plugins-978343ed03d3327597fa3317901f1c1741a7e3c4.tar.gz
check_dig: Add feature to require or forbid dig DNS flags -E, -X.
Introduced helper functions for flag parsing. -E, --require-flags=LIST Comma-separated dig flags that must be present (e.g. 'aa,qr') -X, --forbid-flags=LIST Comma-separated dig flags that must NOT be present
-rw-r--r--plugins/check_dig.c153
-rw-r--r--plugins/check_dig.d/config.h4
2 files changed, 155 insertions, 2 deletions
diff --git a/plugins/check_dig.c b/plugins/check_dig.c
index c27e5f13..b3f4c878 100644
--- a/plugins/check_dig.c
+++ b/plugins/check_dig.c
@@ -36,6 +36,7 @@ const char *progname = "check_dig";
36const char *copyright = "2002-2024"; 36const char *copyright = "2002-2024";
37const char *email = "devel@monitoring-plugins.org"; 37const char *email = "devel@monitoring-plugins.org";
38 38
39#include <ctype.h>
39#include "common.h" 40#include "common.h"
40#include "netutils.h" 41#include "netutils.h"
41#include "utils.h" 42#include "utils.h"
@@ -56,6 +57,12 @@ void print_usage(void);
56 57
57static int verbose = 0; 58static int verbose = 0;
58 59
60/* helpers for flag parsing */
61static bool parse_flags_line(const char *line, char ***out_flags, size_t *out_count);
62static void free_flags(char **flags, size_t count);
63static bool list_contains(char **flags, size_t count, const char *needle);
64static void split_csv_trim(const char *csv, char ***out_items, size_t *out_count);
65
59int main(int argc, char **argv) { 66int main(int argc, char **argv) {
60 setlocale(LC_ALL, ""); 67 setlocale(LC_ALL, "");
61 bindtextdomain(PACKAGE, LOCALEDIR); 68 bindtextdomain(PACKAGE, LOCALEDIR);
@@ -101,6 +108,9 @@ int main(int argc, char **argv) {
101 output chld_out; 108 output chld_out;
102 output chld_err; 109 output chld_err;
103 char *msg = NULL; 110 char *msg = NULL;
111 char **dig_flags = NULL;
112 size_t dig_flags_cnt = 0;
113
104 mp_state_enum result = STATE_UNKNOWN; 114 mp_state_enum result = STATE_UNKNOWN;
105 /* run the command */ 115 /* run the command */
106 if (np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) { 116 if (np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) {
@@ -108,6 +118,21 @@ int main(int argc, char **argv) {
108 msg = (char *)_("dig returned an error status"); 118 msg = (char *)_("dig returned an error status");
109 } 119 }
110 120
121 /* extract ';; flags: ...' from stdout (first occurrence) */
122 for (size_t i = 0; i < chld_out.lines; i++) {
123 if (strstr(chld_out.line[i], "flags:")) {
124 if (verbose) printf("Raw flags line: %s\n", chld_out.line[i]);
125 if (parse_flags_line(chld_out.line[i], &dig_flags, &dig_flags_cnt)) {
126 if (verbose) {
127 printf(_("Parsed flags:"));
128 for (size_t k = 0; k < dig_flags_cnt; k++) printf(" %s", dig_flags[k]);
129 printf("\n");
130 }
131 }
132 break;
133 }
134 }
135
111 for (size_t i = 0; i < chld_out.lines; i++) { 136 for (size_t i = 0; i < chld_out.lines; i++) {
112 /* the server is responding, we just got the host name... */ 137 /* the server is responding, we just got the host name... */
113 if (strstr(chld_out.line[i], ";; ANSWER SECTION:")) { 138 if (strstr(chld_out.line[i], ";; ANSWER SECTION:")) {
@@ -174,6 +199,49 @@ int main(int argc, char **argv) {
174 result = STATE_WARNING; 199 result = STATE_WARNING;
175 } 200 }
176 201
202 /* Optional: evaluate dig flags only if -E/-X were provided */
203 if ((config.require_flags && *config.require_flags) || (config.forbid_flags && *config.forbid_flags)) {
204 if (dig_flags_cnt > 0) {
205 if (config.require_flags && *config.require_flags) {
206 char **req = NULL; size_t reqn = 0;
207 split_csv_trim(config.require_flags, &req, &reqn);
208 for (size_t r = 0; r < reqn; r++) {
209 if (!list_contains(dig_flags, dig_flags_cnt, req[r])) {
210 result = STATE_CRITICAL;
211 if (!msg) {
212 xasprintf(&msg, _("Missing required DNS flag: %s"), req[r]);
213 } else {
214 char *newmsg = NULL;
215 xasprintf(&newmsg, _("%s; missing required DNS flag: %s"), msg, req[r]);
216 msg = newmsg;
217 }
218 }
219 }
220 free_flags(req, reqn);
221 }
222 if (config.forbid_flags && *config.forbid_flags) {
223 char **bad = NULL; size_t badn = 0;
224 split_csv_trim(config.forbid_flags, &bad, &badn);
225 for (size_t r = 0; r < badn; r++) {
226 if (list_contains(dig_flags, dig_flags_cnt, bad[r])) {
227 result = STATE_CRITICAL;
228 if (!msg) {
229 xasprintf(&msg, _("Forbidden DNS flag present: %s"), bad[r]);
230 } else {
231 char *newmsg = NULL;
232 xasprintf(&newmsg, _("%s; forbidden DNS flag present: %s"), msg, bad[r]);
233 msg = newmsg;
234 }
235 }
236 }
237 free_flags(bad, badn);
238 }
239 }
240 }
241
242 /* cleanup flags buffer */
243 free_flags(dig_flags, dig_flags_cnt);
244
177 printf("DNS %s - %.3f seconds response time (%s)|%s\n", state_text(result), elapsed_time, 245 printf("DNS %s - %.3f seconds response time (%s)|%s\n", state_text(result), elapsed_time,
178 msg ? msg : _("Probably a non-existent host/domain"), 246 msg ? msg : _("Probably a non-existent host/domain"),
179 fperfdata("time", elapsed_time, "s", (config.warning_interval > UNDEFINED), 247 fperfdata("time", elapsed_time, "s", (config.warning_interval > UNDEFINED),
@@ -190,6 +258,8 @@ check_dig_config_wrapper process_arguments(int argc, char **argv) {
190 {"critical", required_argument, 0, 'c'}, 258 {"critical", required_argument, 0, 'c'},
191 {"timeout", required_argument, 0, 't'}, 259 {"timeout", required_argument, 0, 't'},
192 {"dig-arguments", required_argument, 0, 'A'}, 260 {"dig-arguments", required_argument, 0, 'A'},
261 {"require-flags", required_argument, 0, 'E'},
262 {"forbid-flags", required_argument, 0, 'X'},
193 {"verbose", no_argument, 0, 'v'}, 263 {"verbose", no_argument, 0, 'v'},
194 {"version", no_argument, 0, 'V'}, 264 {"version", no_argument, 0, 'V'},
195 {"help", no_argument, 0, 'h'}, 265 {"help", no_argument, 0, 'h'},
@@ -212,7 +282,7 @@ check_dig_config_wrapper process_arguments(int argc, char **argv) {
212 282
213 int option = 0; 283 int option = 0;
214 while (true) { 284 while (true) {
215 int option_index = getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option); 285 int option_index = getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:E:X:46", longopts, &option);
216 286
217 if (option_index == -1 || option_index == EOF) { 287 if (option_index == -1 || option_index == EOF) {
218 break; 288 break;
@@ -263,6 +333,12 @@ check_dig_config_wrapper process_arguments(int argc, char **argv) {
263 case 'A': /* dig arguments */ 333 case 'A': /* dig arguments */
264 result.config.dig_args = strdup(optarg); 334 result.config.dig_args = strdup(optarg);
265 break; 335 break;
336 case 'E': /* require flags */
337 result.config.require_flags = strdup(optarg);
338 break;
339 case 'X': /* forbid flags */
340 result.config.forbid_flags = strdup(optarg);
341 break;
266 case 'v': /* verbose */ 342 case 'v': /* verbose */
267 verbose++; 343 verbose++;
268 break; 344 break;
@@ -343,6 +419,10 @@ void print_help(void) {
343 printf(" %s\n", _("was in -l")); 419 printf(" %s\n", _("was in -l"));
344 printf(" %s\n", "-A, --dig-arguments=STRING"); 420 printf(" %s\n", "-A, --dig-arguments=STRING");
345 printf(" %s\n", _("Pass STRING as argument(s) to dig")); 421 printf(" %s\n", _("Pass STRING as argument(s) to dig"));
422 printf(" %s\n", "-E, --require-flags=LIST");
423 printf(" %s\n", _("Comma-separated dig flags that must be present (e.g. 'aa,qr')"));
424 printf(" %s\n", "-X, --forbid-flags=LIST");
425 printf(" %s\n", _("Comma-separated dig flags that must NOT be present"));
346 printf(UT_WARN_CRIT); 426 printf(UT_WARN_CRIT);
347 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 427 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
348 printf(UT_VERBOSE); 428 printf(UT_VERBOSE);
@@ -359,5 +439,74 @@ void print_usage(void) {
359 printf("%s\n", _("Usage:")); 439 printf("%s\n", _("Usage:"));
360 printf("%s -l <query_address> [-H <host>] [-p <server port>]\n", progname); 440 printf("%s -l <query_address> [-H <host>] [-p <server port>]\n", progname);
361 printf(" [-T <query type>] [-w <warning interval>] [-c <critical interval>]\n"); 441 printf(" [-T <query type>] [-w <warning interval>] [-c <critical interval>]\n");
362 printf(" [-t <timeout>] [-a <expected answer address>] [-v]\n"); 442 printf(" [-t <timeout>] [-a <expected answer address>] [-E <flags>] [-X <flags>] [-v]\n");
443}
444
445/* helpers */
446
447static bool parse_flags_line(const char *line, char ***out_flags, size_t *out_count) {
448 if (!line || !out_flags || !out_count) return false;
449 *out_flags = NULL; *out_count = 0;
450
451 const char *p = strstr(line, "flags:");
452 if (!p) return false;
453 p += 6;
454
455 while (*p && isspace((unsigned char)*p)) p++;
456 const char *q = strchr(p, ';');
457 if (!q) return false;
458
459 size_t len = (size_t)(q - p);
460 if (len == 0) return false;
461
462 char *buf = (char*)malloc(len + 1);
463 if (!buf) return false;
464 memcpy(buf, p, len); buf[len] = '\0';
465
466 char **arr = NULL; size_t cnt = 0;
467 char *saveptr = NULL;
468 char *tok = strtok_r(buf, " \t", &saveptr);
469 while (tok) {
470 arr = (char**)realloc(arr, (cnt + 1) * sizeof(char*));
471 arr[cnt++] = strdup(tok);
472 tok = strtok_r(NULL, " \t", &saveptr);
473 }
474 free(buf);
475
476 *out_flags = arr;
477 *out_count = cnt;
478 return (cnt > 0);
479}
480
481static void free_flags(char **flags, size_t count) {
482 if (!flags) return;
483 for (size_t i = 0; i < count; i++) free(flags[i]);
484 free(flags);
485}
486
487static bool list_contains(char **flags, size_t count, const char *needle) {
488 if (!needle || !*needle) return false;
489 for (size_t i = 0; i < count; i++) {
490 if (strcasecmp(flags[i], needle) == 0) return true;
491 }
492 return false;
493}
494
495static void split_csv_trim(const char *csv, char ***out_items, size_t *out_count) {
496 *out_items = NULL; *out_count = 0;
497 if (!csv || !*csv) return;
498
499 char *tmp = strdup(csv);
500 char *s = tmp;
501 char *token = NULL;
502 while ((token = strsep(&s, ",")) != NULL) {
503 while (*token && isspace((unsigned char)*token)) token++;
504 char *end = token + strlen(token);
505 while (end > token && isspace((unsigned char)end[-1])) *--end = '\0';
506 if (*token) {
507 *out_items = (char**)realloc(*out_items, (*out_count + 1) * sizeof(char*));
508 (*out_items)[(*out_count)++] = strdup(token);
509 }
510 }
511 free(tmp);
363} 512}
diff --git a/plugins/check_dig.d/config.h b/plugins/check_dig.d/config.h
index a570b633..392848e5 100644
--- a/plugins/check_dig.d/config.h
+++ b/plugins/check_dig.d/config.h
@@ -19,6 +19,8 @@ typedef struct {
19 19
20 double warning_interval; 20 double warning_interval;
21 double critical_interval; 21 double critical_interval;
22 char *require_flags;
23 char *forbid_flags;
22} check_dig_config; 24} check_dig_config;
23 25
24check_dig_config check_dig_config_init() { 26check_dig_config check_dig_config_init() {
@@ -34,6 +36,8 @@ check_dig_config check_dig_config_init() {
34 36
35 .warning_interval = UNDEFINED, 37 .warning_interval = UNDEFINED,
36 .critical_interval = UNDEFINED, 38 .critical_interval = UNDEFINED,
39 .require_flags = NULL,
40 .forbid_flags = NULL,
37 41
38 }; 42 };
39 return tmp; 43 return tmp;