diff options
Diffstat (limited to 'plugins/check_dns.c')
-rw-r--r-- | plugins/check_dns.c | 108 |
1 files changed, 86 insertions, 22 deletions
diff --git a/plugins/check_dns.c b/plugins/check_dns.c index d6bd2c0..0f2e654 100644 --- a/plugins/check_dns.c +++ b/plugins/check_dns.c | |||
@@ -42,6 +42,8 @@ const char *email = "devel@monitoring-plugins.org"; | |||
42 | int process_arguments (int, char **); | 42 | int process_arguments (int, char **); |
43 | int validate_arguments (void); | 43 | int validate_arguments (void); |
44 | int error_scan (char *); | 44 | int error_scan (char *); |
45 | int ip_match_cidr(const char *, const char *); | ||
46 | unsigned long ip2long(const char *); | ||
45 | void print_help (void); | 47 | void print_help (void); |
46 | void print_usage (void); | 48 | void print_usage (void); |
47 | 49 | ||
@@ -54,6 +56,7 @@ char **expected_address = NULL; | |||
54 | int expected_address_cnt = 0; | 56 | int expected_address_cnt = 0; |
55 | 57 | ||
56 | int expect_authority = FALSE; | 58 | int expect_authority = FALSE; |
59 | int all_match = FALSE; | ||
57 | thresholds *time_thresholds = NULL; | 60 | thresholds *time_thresholds = NULL; |
58 | 61 | ||
59 | static int | 62 | static int |
@@ -81,7 +84,6 @@ main (int argc, char **argv) | |||
81 | double elapsed_time; | 84 | double elapsed_time; |
82 | long microsec; | 85 | long microsec; |
83 | struct timeval tv; | 86 | struct timeval tv; |
84 | int multi_address; | ||
85 | int parse_address = FALSE; /* This flag scans for Address: but only after Name: */ | 87 | int parse_address = FALSE; /* This flag scans for Address: but only after Name: */ |
86 | output chld_out, chld_err; | 88 | output chld_out, chld_err; |
87 | size_t i; | 89 | size_t i; |
@@ -127,7 +129,7 @@ main (int argc, char **argv) | |||
127 | if (verbose) | 129 | if (verbose) |
128 | puts(chld_out.line[i]); | 130 | puts(chld_out.line[i]); |
129 | 131 | ||
130 | if (strstr (chld_out.line[i], ".in-addr.arpa")) { | 132 | if (strcasestr (chld_out.line[i], ".in-addr.arpa") || strcasestr (chld_out.line[i], ".ip6.arpa")) { |
131 | if ((temp_buffer = strstr (chld_out.line[i], "name = "))) | 133 | if ((temp_buffer = strstr (chld_out.line[i], "name = "))) |
132 | addresses[n_addresses++] = strdup (temp_buffer + 7); | 134 | addresses[n_addresses++] = strdup (temp_buffer + 7); |
133 | else { | 135 | else { |
@@ -167,8 +169,8 @@ main (int argc, char **argv) | |||
167 | temp_buffer++; | 169 | temp_buffer++; |
168 | 170 | ||
169 | /* Strip leading spaces */ | 171 | /* Strip leading spaces */ |
170 | for (; *temp_buffer != '\0' && *temp_buffer == ' '; temp_buffer++) | 172 | while (*temp_buffer == ' ') |
171 | /* NOOP */; | 173 | temp_buffer++; |
172 | 174 | ||
173 | strip(temp_buffer); | 175 | strip(temp_buffer); |
174 | if (temp_buffer==NULL || strlen(temp_buffer)==0) { | 176 | if (temp_buffer==NULL || strlen(temp_buffer)==0) { |
@@ -200,7 +202,10 @@ main (int argc, char **argv) | |||
200 | if (error_scan (chld_err.line[i]) != STATE_OK) { | 202 | if (error_scan (chld_err.line[i]) != STATE_OK) { |
201 | result = max_state (result, error_scan (chld_err.line[i])); | 203 | result = max_state (result, error_scan (chld_err.line[i])); |
202 | msg = strchr(input_buffer, ':'); | 204 | msg = strchr(input_buffer, ':'); |
203 | if(msg) msg++; | 205 | if(msg) |
206 | msg++; | ||
207 | else | ||
208 | msg = input_buffer; | ||
204 | } | 209 | } |
205 | } | 210 | } |
206 | 211 | ||
@@ -227,11 +232,27 @@ main (int argc, char **argv) | |||
227 | if (result == STATE_OK && expected_address_cnt > 0) { | 232 | if (result == STATE_OK && expected_address_cnt > 0) { |
228 | result = STATE_CRITICAL; | 233 | result = STATE_CRITICAL; |
229 | temp_buffer = ""; | 234 | temp_buffer = ""; |
235 | unsigned long expect_match = (1 << expected_address_cnt) - 1; | ||
236 | unsigned long addr_match = (1 << n_addresses) - 1; | ||
237 | |||
230 | for (i=0; i<expected_address_cnt; i++) { | 238 | for (i=0; i<expected_address_cnt; i++) { |
231 | /* check if we get a match and prepare an error string */ | 239 | int j; |
232 | if (strcmp(address, expected_address[i]) == 0) result = STATE_OK; | 240 | /* check if we get a match on 'raw' ip or cidr */ |
241 | for (j=0; j<n_addresses; j++) { | ||
242 | if ( strcmp(addresses[j], expected_address[i]) == 0 | ||
243 | || ip_match_cidr(addresses[j], expected_address[i]) ) { | ||
244 | result = STATE_OK; | ||
245 | addr_match &= ~(1 << j); | ||
246 | expect_match &= ~(1 << i); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | /* prepare an error string */ | ||
233 | xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]); | 251 | xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]); |
234 | } | 252 | } |
253 | /* check if expected_address must cover all in addresses and none may be missing */ | ||
254 | if (all_match && (expect_match != 0 || addr_match != 0)) | ||
255 | result = STATE_CRITICAL; | ||
235 | if (result == STATE_CRITICAL) { | 256 | if (result == STATE_CRITICAL) { |
236 | /* Strip off last semicolon... */ | 257 | /* Strip off last semicolon... */ |
237 | temp_buffer[strlen(temp_buffer)-2] = '\0'; | 258 | temp_buffer[strlen(temp_buffer)-2] = '\0'; |
@@ -249,11 +270,6 @@ main (int argc, char **argv) | |||
249 | elapsed_time = (double)microsec / 1.0e6; | 270 | elapsed_time = (double)microsec / 1.0e6; |
250 | 271 | ||
251 | if (result == STATE_OK) { | 272 | if (result == STATE_OK) { |
252 | if (strchr (address, ',') == NULL) | ||
253 | multi_address = FALSE; | ||
254 | else | ||
255 | multi_address = TRUE; | ||
256 | |||
257 | result = get_status(elapsed_time, time_thresholds); | 273 | result = get_status(elapsed_time, time_thresholds); |
258 | if (result == STATE_OK) { | 274 | if (result == STATE_OK) { |
259 | printf ("DNS %s: ", _("OK")); | 275 | printf ("DNS %s: ", _("OK")); |
@@ -295,7 +311,32 @@ main (int argc, char **argv) | |||
295 | return result; | 311 | return result; |
296 | } | 312 | } |
297 | 313 | ||
314 | int | ||
315 | ip_match_cidr(const char *addr, const char *cidr_ro) | ||
316 | { | ||
317 | char *subnet, *mask_c, *cidr = strdup(cidr_ro); | ||
318 | int mask; | ||
319 | subnet = strtok(cidr, "/"); | ||
320 | mask_c = strtok(NULL, "\0"); | ||
321 | if (!subnet || !mask_c) | ||
322 | return FALSE; | ||
323 | mask = atoi(mask_c); | ||
324 | |||
325 | /* https://www.cryptobells.com/verifying-ips-in-a-subnet-in-php/ */ | ||
326 | return (ip2long(addr) & ~((1 << (32 - mask)) - 1)) == (ip2long(subnet) >> (32 - mask)) << (32 - mask); | ||
327 | } | ||
298 | 328 | ||
329 | unsigned long | ||
330 | ip2long(const char* src) { | ||
331 | unsigned long ip[4]; | ||
332 | /* http://computer-programming-forum.com/47-c-language/1376ffb92a12c471.htm */ | ||
333 | return (sscanf(src, "%3lu.%3lu.%3lu.%3lu", | ||
334 | &ip[0], &ip[1], &ip[2], &ip[3]) == 4 && | ||
335 | ip[0] < 256 && ip[1] < 256 && | ||
336 | ip[2] < 256 && ip[3] < 256) | ||
337 | ? ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3] | ||
338 | : 0; | ||
339 | } | ||
299 | 340 | ||
300 | int | 341 | int |
301 | error_scan (char *input_buffer) | 342 | error_scan (char *input_buffer) |
@@ -310,6 +351,8 @@ error_scan (char *input_buffer) | |||
310 | /* DNS server is not running... */ | 351 | /* DNS server is not running... */ |
311 | else if (strstr (input_buffer, "No response from server")) | 352 | else if (strstr (input_buffer, "No response from server")) |
312 | die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server); | 353 | die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server); |
354 | else if (strstr (input_buffer, "no servers could be reached")) | ||
355 | die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server); | ||
313 | 356 | ||
314 | /* Host name is valid, but server doesn't have records... */ | 357 | /* Host name is valid, but server doesn't have records... */ |
315 | else if (strstr (input_buffer, "No records")) | 358 | else if (strstr (input_buffer, "No records")) |
@@ -334,6 +377,7 @@ error_scan (char *input_buffer) | |||
334 | /* Host or domain name does not exist */ | 377 | /* Host or domain name does not exist */ |
335 | else if (strstr (input_buffer, "Non-existent") || | 378 | else if (strstr (input_buffer, "Non-existent") || |
336 | strstr (input_buffer, "** server can't find") || | 379 | strstr (input_buffer, "** server can't find") || |
380 | strstr (input_buffer, "** Can't find") || | ||
337 | strstr (input_buffer,"NXDOMAIN")) | 381 | strstr (input_buffer,"NXDOMAIN")) |
338 | die (STATE_CRITICAL, _("Domain %s was not found by the server\n"), query_address); | 382 | die (STATE_CRITICAL, _("Domain %s was not found by the server\n"), query_address); |
339 | 383 | ||
@@ -374,6 +418,7 @@ process_arguments (int argc, char **argv) | |||
374 | {"reverse-server", required_argument, 0, 'r'}, | 418 | {"reverse-server", required_argument, 0, 'r'}, |
375 | {"expected-address", required_argument, 0, 'a'}, | 419 | {"expected-address", required_argument, 0, 'a'}, |
376 | {"expect-authority", no_argument, 0, 'A'}, | 420 | {"expect-authority", no_argument, 0, 'A'}, |
421 | {"all", no_argument, 0, 'L'}, | ||
377 | {"warning", required_argument, 0, 'w'}, | 422 | {"warning", required_argument, 0, 'w'}, |
378 | {"critical", required_argument, 0, 'c'}, | 423 | {"critical", required_argument, 0, 'c'}, |
379 | {0, 0, 0, 0} | 424 | {0, 0, 0, 0} |
@@ -387,7 +432,7 @@ process_arguments (int argc, char **argv) | |||
387 | strcpy (argv[c], "-t"); | 432 | strcpy (argv[c], "-t"); |
388 | 433 | ||
389 | while (1) { | 434 | while (1) { |
390 | c = getopt_long (argc, argv, "hVvAt:H:s:r:a:w:c:", long_opts, &opt_index); | 435 | c = getopt_long (argc, argv, "hVvALt:H:s:r:a:w:c:", long_opts, &opt_index); |
391 | 436 | ||
392 | if (c == -1 || c == EOF) | 437 | if (c == -1 || c == EOF) |
393 | break; | 438 | break; |
@@ -428,13 +473,30 @@ process_arguments (int argc, char **argv) | |||
428 | case 'a': /* expected address */ | 473 | case 'a': /* expected address */ |
429 | if (strlen (optarg) >= ADDRESS_LENGTH) | 474 | if (strlen (optarg) >= ADDRESS_LENGTH) |
430 | die (STATE_UNKNOWN, _("Input buffer overflow\n")); | 475 | die (STATE_UNKNOWN, _("Input buffer overflow\n")); |
431 | expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**)); | 476 | if (strchr(optarg, ',') != NULL) { |
432 | expected_address[expected_address_cnt] = strdup(optarg); | 477 | char *comma = strchr(optarg, ','); |
433 | expected_address_cnt++; | 478 | while (comma != NULL) { |
479 | expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**)); | ||
480 | expected_address[expected_address_cnt] = strndup(optarg, comma - optarg); | ||
481 | expected_address_cnt++; | ||
482 | optarg = comma + 1; | ||
483 | comma = strchr(optarg, ','); | ||
484 | } | ||
485 | expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**)); | ||
486 | expected_address[expected_address_cnt] = strdup(optarg); | ||
487 | expected_address_cnt++; | ||
488 | } else { | ||
489 | expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**)); | ||
490 | expected_address[expected_address_cnt] = strdup(optarg); | ||
491 | expected_address_cnt++; | ||
492 | } | ||
434 | break; | 493 | break; |
435 | case 'A': /* expect authority */ | 494 | case 'A': /* expect authority */ |
436 | expect_authority = TRUE; | 495 | expect_authority = TRUE; |
437 | break; | 496 | break; |
497 | case 'L': /* all must match */ | ||
498 | all_match = TRUE; | ||
499 | break; | ||
438 | case 'w': | 500 | case 'w': |
439 | warning = optarg; | 501 | warning = optarg; |
440 | break; | 502 | break; |
@@ -500,17 +562,19 @@ print_help (void) | |||
500 | printf (" %s\n", _("The name or address you want to query")); | 562 | printf (" %s\n", _("The name or address you want to query")); |
501 | printf (" -s, --server=HOST\n"); | 563 | printf (" -s, --server=HOST\n"); |
502 | printf (" %s\n", _("Optional DNS server you want to use for the lookup")); | 564 | printf (" %s\n", _("Optional DNS server you want to use for the lookup")); |
503 | printf (" -a, --expected-address=IP-ADDRESS|HOST\n"); | 565 | printf (" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n"); |
504 | printf (" %s\n", _("Optional IP-ADDRESS you expect the DNS server to return. HOST must end with")); | 566 | printf (" %s\n", _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end")); |
505 | printf (" %s\n", _("a dot (.). This option can be repeated multiple times (Returns OK if any")); | 567 | printf (" %s\n", _("with a dot (.). This option can be repeated multiple times (Returns OK if any")); |
506 | printf (" %s\n", _("value match). If multiple addresses are returned at once, you have to match")); | 568 | printf (" %s\n", _("value matches).")); |
507 | printf (" %s\n", _("the whole string of addresses separated with commas (sorted alphabetically).")); | ||
508 | printf (" -A, --expect-authority\n"); | 569 | printf (" -A, --expect-authority\n"); |
509 | printf (" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup")); | 570 | printf (" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup")); |
510 | printf (" -w, --warning=seconds\n"); | 571 | printf (" -w, --warning=seconds\n"); |
511 | printf (" %s\n", _("Return warning if elapsed time exceeds value. Default off")); | 572 | printf (" %s\n", _("Return warning if elapsed time exceeds value. Default off")); |
512 | printf (" -c, --critical=seconds\n"); | 573 | printf (" -c, --critical=seconds\n"); |
513 | printf (" %s\n", _("Return critical if elapsed time exceeds value. Default off")); | 574 | printf (" %s\n", _("Return critical if elapsed time exceeds value. Default off")); |
575 | printf (" -L, --all\n"); | ||
576 | printf (" %s\n", _("Return critical if the list of expected addresses does not match all addresses")); | ||
577 | printf (" %s\n", _("returned. Default off")); | ||
514 | 578 | ||
515 | printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); | 579 | printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); |
516 | 580 | ||
@@ -522,5 +586,5 @@ void | |||
522 | print_usage (void) | 586 | print_usage (void) |
523 | { | 587 | { |
524 | printf ("%s\n", _("Usage:")); | 588 | printf ("%s\n", _("Usage:")); |
525 | printf ("%s -H host [-s server] [-a expected-address] [-A] [-t timeout] [-w warn] [-c crit]\n", progname); | 589 | printf ("%s -H host [-s server] [-a expected-address] [-A] [-t timeout] [-w warn] [-c crit] [-L]\n", progname); |
526 | } | 590 | } |