X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=plugins%2Fcheck_dns.c;h=a921429859dd8320d9d292575a01e0a8f299a12e;hb=25d1ee331dbe4977a4a1a756c67f32bd51d9b070;hp=309c65b7ca04344f6601c3e3d9c552f809e00d8e;hpb=46e26edd7f68a3870b56dc1311f7d9b6eee7ee1f;p=nagiosplug.git diff --git a/plugins/check_dns.c b/plugins/check_dns.c index 309c65b..a921429 100644 --- a/plugins/check_dns.c +++ b/plugins/check_dns.c @@ -1,58 +1,43 @@ -/****************************************************************************** - * - * CHECK_DNS.C - * - * Program: DNS plugin for Nagios - * License: GPL - * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org) - * - * Last Modified: $Date$ - * - * Notes: - * - Safe popen added by Karl DeBisschop 9-11-99 - * - expected-address parameter added by Alex Chaffee - 7 Oct 2002 - * - * Command line: (see print_usage) - * - * Description: - * - * This program will use the nslookup program to obtain the IP address - * for a given host name. A optional DNS server may be specified. If - * no DNS server is specified, the default server(s) for the system - * are used. - * - * Return Values: - * OK The DNS query was successful (host IP address was returned). - * WARNING The DNS server responded, but could not fulfill the request. - * CRITICAL The DNS server is not responding or encountered an error. - * - * License Information: - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - *****************************************************************************/ +/***************************************************************************** +* +* Nagios check_dns plugin +* +* License: GPL +* Copyright (c) 2000-2008 Nagios Plugins Development Team +* +* Description: +* +* This file contains the check_dns plugin +* +* LIMITATION: nslookup on Solaris 7 can return output over 2 lines, which +* will not be picked up by this plugin +* +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* +*****************************************************************************/ + +const char *progname = "check_dns"; +const char *copyright = "2000-2008"; +const char *email = "nagiosplug-devel@lists.sourceforge.net"; #include "common.h" -#include "popen.h" #include "utils.h" +#include "utils_base.h" #include "netutils.h" - -const char *progname = "check_dns"; -const char *revision = "$Revision$"; -const char *copyright = "2000-2003"; -const char *email = "nagiosplug-devel@lists.sourceforge.net"; +#include "runcmd.h" int process_arguments (int, char **); int validate_arguments (void); @@ -65,379 +50,445 @@ char query_address[ADDRESS_LENGTH] = ""; char dns_server[ADDRESS_LENGTH] = ""; char ptr_server[ADDRESS_LENGTH] = ""; int verbose = FALSE; -char expected_address[ADDRESS_LENGTH] = ""; -int match_expected_address = FALSE; +char **expected_address = NULL; +int expected_address_cnt = 0; -int -main (int argc, char **argv) +int expect_authority = FALSE; +thresholds *time_thresholds = NULL; + +static int +qstrcmp(const void *p1, const void *p2) { - char *command_line = NULL; - char input_buffer[MAX_INPUT_BUFFER]; - char *output = NULL; - char *address = NULL; - char *temp_buffer = NULL; - int result = STATE_UNKNOWN; - double elapsed_time; - long microsec; - struct timeval tv; - int multi_address; - - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - /* Set signal handling and alarm */ - if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) { - printf (_("Cannot catch SIGALRM")); - return STATE_UNKNOWN; - } - - if (process_arguments (argc, argv) != OK) { - print_usage (); - return STATE_UNKNOWN; - } - - /* get the command to run */ - asprintf (&command_line, "%s %s %s", NSLOOKUP_COMMAND, query_address, dns_server); - - alarm (timeout_interval); - gettimeofday (&tv, NULL); - - if (verbose) - printf ("%s\n", command_line); - /* run the command */ - child_process = spopen (command_line); - if (child_process == NULL) { - printf (_("Could not open pipe: %s\n"), command_line); - return STATE_UNKNOWN; - } - - child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); - if (child_stderr == NULL) - printf (_("Could not open stderr for %s\n"), command_line); - - /* scan stdout */ - while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { - - if (verbose) - printf ("%s\n", input_buffer); - - if (strstr (input_buffer, ".in-addr.arpa")) { - if ((temp_buffer = strstr (input_buffer, "name = "))) - address = strdup (temp_buffer + 7); - else { - output = strdup (_("Unknown error (plugin)")); - result = STATE_WARNING; - } - } - - /* the server is responding, we just got the host name... */ - if (strstr (input_buffer, "Name:")) { - - /* get the host address */ - if (!fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) - break; - - if (verbose) - printf ("%s\n", input_buffer); - - if ((temp_buffer = index (input_buffer, ':'))) { - temp_buffer++; - /* Strip leading spaces */ - for (; *temp_buffer != '\0' && *temp_buffer == ' '; temp_buffer++) - /* NOOP */; - address = strdup (temp_buffer); - strip (address); - if (address==NULL || strlen(address)==0) - die (STATE_CRITICAL, - _("DNS CRITICAL - '%s' returned empty host name string\n"), - NSLOOKUP_COMMAND); - result = STATE_OK; - } - else { - output = strdup (_("Unknown error (plugin)")); - result = STATE_WARNING; - } - - break; - } - - result = error_scan (input_buffer); - if (result != STATE_OK) { - output = strdup (1 + index (input_buffer, ':')); - strip (output); - break; - } - - } - - /* scan stderr */ - while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) { - if (error_scan (input_buffer) != STATE_OK) { - result = max_state (result, error_scan (input_buffer)); - output = strdup (1 + index (input_buffer, ':')); - strip (output); - } - } - - /* close stderr */ - (void) fclose (child_stderr); - - /* close stdout */ - if (spclose (child_process)) { - result = max_state (result, STATE_WARNING); - if (!strcmp (output, "")) - output = strdup (_("nslookup returned error status")); - } - - /* If we got here, we should have an address string, - and we can segfault if we do not */ - if (address==NULL || strlen(address)==0) - die (STATE_CRITICAL, - _("DNS CRITICAL - '%s' output parsing exited with no address\n"), - NSLOOKUP_COMMAND); - - /* compare to expected address */ - if (result == STATE_OK && match_expected_address && strcmp(address, expected_address)) { - result = STATE_CRITICAL; - asprintf(&output, _("expected %s but got %s"), expected_address, address); - } - - microsec = deltime (tv); - elapsed_time = (double)microsec / 1.0e6; - - if (result == STATE_OK) { - if (strchr (address, ',') == NULL) - multi_address = FALSE; - else - multi_address = TRUE; - - printf (_("DNS ok - %.3f seconds response time, address%s %s|%s\n"), - elapsed_time, (multi_address==TRUE ? "es are" : " is"), address, - perfdata ("time", microsec, "us", FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0)); - } - else if (result == STATE_WARNING) - printf (_("DNS WARNING - %s\n"), - !strcmp (output, "") ? _(" Probably a non-existent host/domain") : output); - else if (result == STATE_CRITICAL) - printf (_("DNS CRITICAL - %s\n"), - !strcmp (output, "") ? _(" Probably a non-existent host/domain") : output); - else - printf (_("DNS problem - %s\n"), - !strcmp (output, "") ? _(" Probably a non-existent host/domain") : output); - - return result; + /* The actual arguments to this function are "pointers to + pointers to char", but strcmp() arguments are "pointers + to char", hence the following cast plus dereference */ + return strcmp(* (char * const *) p1, * (char * const *) p2); } + int -error_scan (char *input_buffer) +main (int argc, char **argv) { + char *command_line = NULL; + char input_buffer[MAX_INPUT_BUFFER]; + char *address = NULL; /* comma seperated str with addrs/ptrs (sorted) */ + char **addresses = NULL; + int n_addresses = 0; + char *msg = NULL; + char *temp_buffer = NULL; + int non_authoritative = FALSE; + int result = STATE_UNKNOWN; + double elapsed_time; + long microsec; + struct timeval tv; + int multi_address; + int parse_address = FALSE; /* This flag scans for Address: but only after Name: */ + output chld_out, chld_err; + size_t i; + + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + /* Set signal handling and alarm */ + if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) { + usage_va(_("Cannot catch SIGALRM")); + } + + /* Parse extra opts if any */ + argv=np_extra_opts (&argc, argv, progname); + + if (process_arguments (argc, argv) == ERROR) { + usage_va(_("Could not parse arguments")); + } + + /* get the command to run */ + asprintf (&command_line, "%s %s %s", NSLOOKUP_COMMAND, query_address, dns_server); + + alarm (timeout_interval); + gettimeofday (&tv, NULL); + + if (verbose) + printf ("%s\n", command_line); + + /* run the command */ + if((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) { + msg = (char *)_("nslookup returned an error status"); + result = STATE_WARNING; + } + + /* scan stdout */ + for(i = 0; i < chld_out.lines; i++) { + if (addresses == NULL) + addresses = malloc(sizeof(*addresses)*10); + else if (!(n_addresses % 10)) + addresses = realloc(addresses,sizeof(*addresses) * (n_addresses + 10)); + + if (verbose) + puts(chld_out.line[i]); + + if (strstr (chld_out.line[i], ".in-addr.arpa")) { + if ((temp_buffer = strstr (chld_out.line[i], "name = "))) + addresses[n_addresses++] = strdup (temp_buffer + 7); + else { + msg = (char *)_("Warning plugin error"); + result = STATE_WARNING; + } + } + + /* the server is responding, we just got the host name... */ + if (strstr (chld_out.line[i], "Name:")) + parse_address = TRUE; + else if (parse_address == TRUE && (strstr (chld_out.line[i], "Address:") || + strstr (chld_out.line[i], "Addresses:"))) { + temp_buffer = index (chld_out.line[i], ':'); + temp_buffer++; + + /* Strip leading spaces */ + for (; *temp_buffer != '\0' && *temp_buffer == ' '; temp_buffer++) + /* NOOP */; + + strip(temp_buffer); + if (temp_buffer==NULL || strlen(temp_buffer)==0) { + die (STATE_CRITICAL, + _("DNS CRITICAL - '%s' returned empty host name string\n"), + NSLOOKUP_COMMAND); + } + + addresses[n_addresses++] = strdup(temp_buffer); + } + else if (strstr (chld_out.line[i], _("Non-authoritative answer:"))) { + non_authoritative = TRUE; + } + + + result = error_scan (chld_out.line[i]); + if (result != STATE_OK) { + msg = strchr (chld_out.line[i], ':'); + if(msg) msg++; + break; + } + } + + /* scan stderr */ + for(i = 0; i < chld_err.lines; i++) { + if (verbose) + puts(chld_err.line[i]); + + if (error_scan (chld_err.line[i]) != STATE_OK) { + result = max_state (result, error_scan (chld_err.line[i])); + msg = strchr(input_buffer, ':'); + if(msg) msg++; + } + } + + if (addresses) { + int i,slen; + char *adrp; + qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp); + for(i=0, slen=1; i < n_addresses; i++) { + slen += strlen(addresses[i])+1; + } + adrp = address = malloc(slen); + for(i=0; i < n_addresses; i++) { + if (i) *adrp++ = ','; + strcpy(adrp, addresses[i]); + adrp += strlen(addresses[i]); + } + *adrp = 0; + } else + die (STATE_CRITICAL, + _("DNS CRITICAL - '%s' msg parsing exited with no address\n"), + NSLOOKUP_COMMAND); + + /* compare to expected address */ + if (result == STATE_OK && expected_address_cnt > 0) { + result = STATE_CRITICAL; + temp_buffer = ""; + for (i=0; i= ADDRESS_LENGTH) - die (STATE_UNKNOWN, _("Input buffer overflow\n")); - strcpy (query_address, optarg); - break; - case 's': /* server name */ - /* TODO: this is_host check is probably unnecessary. Better to confirm nslookup - response matches */ - if (is_host (optarg) == FALSE) { - printf (_("Invalid server name/address\n\n")); - print_usage (); - exit (STATE_UNKNOWN); - } - if (strlen (optarg) >= ADDRESS_LENGTH) - die (STATE_UNKNOWN, _("Input buffer overflow\n")); - strcpy (dns_server, optarg); - break; - case 'r': /* reverse server name */ - /* TODO: Is this is_host necessary? */ - if (is_host (optarg) == FALSE) { - printf (_("Invalid host name/address\n\n")); - print_usage (); - exit (STATE_UNKNOWN); - } - if (strlen (optarg) >= ADDRESS_LENGTH) - die (STATE_UNKNOWN, _("Input buffer overflow\n")); - strcpy (ptr_server, optarg); - break; - case 'a': /* expected address */ - if (strlen (optarg) >= ADDRESS_LENGTH) - die (STATE_UNKNOWN, _("Input buffer overflow\n")); - strcpy (expected_address, optarg); - match_expected_address = TRUE; - break; - } - } - - c = optind; - if (strlen(query_address)==0 && c=ADDRESS_LENGTH) - die (STATE_UNKNOWN, _("Input buffer overflow\n")); - strcpy (query_address, argv[c++]); - } - - if (strlen(dns_server)==0 && c= ADDRESS_LENGTH) - die (STATE_UNKNOWN, _("Input buffer overflow\n")); - strcpy (dns_server, argv[c++]); - } - - return validate_arguments (); + int c; + char *warning = NULL; + char *critical = NULL; + + int opt_index = 0; + static struct option long_opts[] = { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {"timeout", required_argument, 0, 't'}, + {"hostname", required_argument, 0, 'H'}, + {"server", required_argument, 0, 's'}, + {"reverse-server", required_argument, 0, 'r'}, + {"expected-address", required_argument, 0, 'a'}, + {"expect-authority", no_argument, 0, 'A'}, + {"warning", required_argument, 0, 'w'}, + {"critical", required_argument, 0, 'c'}, + {0, 0, 0, 0} + }; + + if (argc < 2) + return ERROR; + + for (c = 1; c < argc; c++) + if (strcmp ("-to", argv[c]) == 0) + strcpy (argv[c], "-t"); + + while (1) { + c = getopt_long (argc, argv, "hVvAt:H:s:r:a:w:c:", long_opts, &opt_index); + + if (c == -1 || c == EOF) + break; + + switch (c) { + case 'h': /* help */ + print_help (); + exit (STATE_OK); + case 'V': /* version */ + print_revision (progname, NP_VERSION); + exit (STATE_OK); + case 'v': /* version */ + verbose = TRUE; + break; + case 't': /* timeout period */ + timeout_interval = atoi (optarg); + break; + case 'H': /* hostname */ + if (strlen (optarg) >= ADDRESS_LENGTH) + die (STATE_UNKNOWN, _("Input buffer overflow\n")); + strcpy (query_address, optarg); + break; + case 's': /* server name */ + /* TODO: this host_or_die check is probably unnecessary. + * Better to confirm nslookup response matches */ + host_or_die(optarg); + if (strlen (optarg) >= ADDRESS_LENGTH) + die (STATE_UNKNOWN, _("Input buffer overflow\n")); + strcpy (dns_server, optarg); + break; + case 'r': /* reverse server name */ + /* TODO: Is this host_or_die necessary? */ + host_or_die(optarg); + if (strlen (optarg) >= ADDRESS_LENGTH) + die (STATE_UNKNOWN, _("Input buffer overflow\n")); + strcpy (ptr_server, optarg); + break; + case 'a': /* expected address */ + if (strlen (optarg) >= ADDRESS_LENGTH) + die (STATE_UNKNOWN, _("Input buffer overflow\n")); + expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**)); + expected_address[expected_address_cnt] = strdup(optarg); + expected_address_cnt++; + break; + case 'A': /* expect authority */ + expect_authority = TRUE; + break; + case 'w': + warning = optarg; + break; + case 'c': + critical = optarg; + break; + default: /* args not parsable */ + usage5(); + } + } + + c = optind; + if (strlen(query_address)==0 && c=ADDRESS_LENGTH) + die (STATE_UNKNOWN, _("Input buffer overflow\n")); + strcpy (query_address, argv[c++]); + } + + if (strlen(dns_server)==0 && c= ADDRESS_LENGTH) + die (STATE_UNKNOWN, _("Input buffer overflow\n")); + strcpy (dns_server, argv[c++]); + } + + set_thresholds(&time_thresholds, warning, critical); + + return validate_arguments (); } + int validate_arguments () { - if (query_address[0] == 0) - return ERROR; - else - return OK; -} - - + if (query_address[0] == 0) + return ERROR; + return OK; +} - void print_help (void) { - print_revision (progname, revision); - - printf (_("Copyright (c) 1999 Ethan Galstad \n")); - printf (_(COPYRIGHT), copyright, email); - - print_usage (); - - printf (_(UT_HELP_VRSN)); - - printf (_("\ --H, --hostname=HOST\n\ - The name or address you want to query\n\ --s, --server=HOST\n\ - Optional DNS server you want to use for the lookup\n\ --a, --expected-address=IP-ADDRESS\n\ - Optional IP address you expect the DNS server to return\n")); - - printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT); - - printf (_("\n\ -This plugin uses the nslookup program to obtain the IP address\n\ -for the given host/domain query. A optional DNS server to use may\n\ -be specified. If no DNS server is specified, the default server(s)\n\ -specified in /etc/resolv.conf will be used.\n")); - - printf (_(UT_SUPPORT)); + print_revision (progname, NP_VERSION); + + printf ("Copyright (c) 1999 Ethan Galstad \n"); + printf (COPYRIGHT, copyright, email); + + printf ("%s\n", _("This plugin uses the nslookup program to obtain the IP address for the given host/domain query.")); + printf ("%s\n", _("An optional DNS server to use may be specified.")); + printf ("%s\n", _("If no DNS server is specified, the default server(s) specified in /etc/resolv.conf will be used.")); + + printf ("\n\n"); + + print_usage (); + + printf (UT_HELP_VRSN); + printf (UT_EXTRA_OPTS); + + printf (" -H, --hostname=HOST\n"); + printf (" %s\n", _("The name or address you want to query")); + printf (" -s, --server=HOST\n"); + printf (" %s\n", _("Optional DNS server you want to use for the lookup")); + printf (" -a, --expected-address=IP-ADDRESS|HOST\n"); + printf (" %s\n", _("Optional IP-ADDRESS you expect the DNS server to return. HOST must end with")); + printf (" %s\n", _("a dot (.). This option can be repeated multiple times (Returns OK if any")); + printf (" %s\n", _("value match). If multiple addresses are returned at once, you have to match")); + printf (" %s\n", _("the whole string of addresses separated with commas (sorted alphabetically).")); + printf (" -A, --expect-authority\n"); + printf (" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup")); + printf (" -w, --warning=seconds\n"); + printf (" %s\n", _("Return warning if elapsed time exceeds value. Default off")); + printf (" -c, --critical=seconds\n"); + printf (" %s\n", _("Return critical if elapsed time exceeds value. Default off")); + + printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); + +#ifdef NP_EXTRA_OPTS + printf ("\n"); + printf ("%s\n", _("Notes:")); + printf (UT_EXTRA_OPTS_NOTES); +#endif + + printf (UT_SUPPORT); } - - void print_usage (void) { - printf (_("\ -Usage: %s -H host [-s server] [-a expected-address] [-t timeout]\n\ - %s --help\n\ - %s --version\n"), - progname, progname, progname); + printf (_("Usage:")); + printf ("%s -H host [-s server] [-a expected-address] [-A] [-t timeout] [-w warn] [-c crit]\n", progname); }