Code

1fc4039fe590e849c7cb9e0f3d3ce60c0b3e2f18
[nagiosplug.git] / plugins / check_dns.c
1 /******************************************************************************
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; either version 2 of the License, or
6  (at your option) any later version.
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  GNU General Public License for more details.
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 ******************************************************************************/
19 #include "common.h"
20 #include "popen.h"
21 #include "utils.h"
22 #include "netutils.h"
24 const char *progname = "check_dns";
25 const char *revision = "$Revision$";
26 const char *copyright = "2000-2004";
27 const char *email = "nagiosplug-devel@lists.sourceforge.net";
29 int process_arguments (int, char **);
30 int validate_arguments (void);
31 int error_scan (char *);
32 void print_help (void);
33 void print_usage (void);
35 #define ADDRESS_LENGTH 256
36 char query_address[ADDRESS_LENGTH] = "";
37 char dns_server[ADDRESS_LENGTH] = "";
38 char ptr_server[ADDRESS_LENGTH] = "";
39 int verbose = FALSE;
40 char expected_address[ADDRESS_LENGTH] = "";
41 int match_expected_address = FALSE;
43 int
44 main (int argc, char **argv)
45 {
46         char *command_line = NULL;
47         char input_buffer[MAX_INPUT_BUFFER];
48         char *output = NULL;
49         char *address = NULL;
50         char *temp_buffer = NULL;
51         int result = STATE_UNKNOWN;
52         double elapsed_time;
53         long microsec;
54         struct timeval tv;
55         int multi_address;
56         int parse_address = FALSE;      /* This flag scans for Address: but only after Name: */
58         setlocale (LC_ALL, "");
59         bindtextdomain (PACKAGE, LOCALEDIR);
60         textdomain (PACKAGE);
62         /* Set signal handling and alarm */
63         if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
64                 printf (_("Cannot catch SIGALRM"));
65                 return STATE_UNKNOWN;
66         }
68         if (process_arguments (argc, argv) != OK) {
69                 print_usage ();
70                 return STATE_UNKNOWN;
71         }
73         /* get the command to run */
74         asprintf (&command_line, "%s %s %s", NSLOOKUP_COMMAND,  query_address, dns_server);
76         alarm (timeout_interval);
77         gettimeofday (&tv, NULL);
79         if (verbose)
80                 printf ("%s\n", command_line);
82         /* run the command */
83         child_process = spopen (command_line);
84         if (child_process == NULL) {
85                 printf (_("Could not open pipe: %s\n"), command_line);
86                 return STATE_UNKNOWN;
87         }
89         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
90         if (child_stderr == NULL)
91                 printf (_("Could not open stderr for %s\n"), command_line);
93         /* scan stdout */
94         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
96                 if (verbose)
97                         printf ("%s", input_buffer);
99                 if (strstr (input_buffer, ".in-addr.arpa")) {
100                         if ((temp_buffer = strstr (input_buffer, "name = ")))
101                                 address = strdup (temp_buffer + 7);
102                         else {
103                                 output = strdup (_("Unknown error (plugin)"));
104                                 result = STATE_WARNING;
105                         }
106                 }
108                 /* the server is responding, we just got the host name... */
109                 if (strstr (input_buffer, "Name:"))
110                         parse_address = TRUE;
111                 else if (strstr (input_buffer, "Address:") && parse_address == TRUE) {
112                         temp_buffer = index (input_buffer, ':');
113                         temp_buffer++;
115                         /* Strip leading spaces */
116                         for (; *temp_buffer != '\0' && *temp_buffer == ' '; temp_buffer++)
117                                 /* NOOP */;
118                         
119                         strip(temp_buffer);
120                         if (temp_buffer==NULL || strlen(temp_buffer)==0) {
121                                 die (STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty host name string\n"),
122                                                                                  NSLOOKUP_COMMAND);
123                         }
125                         if (address == NULL)
126                                 address = strdup (temp_buffer);
127                         else
128                                 asprintf(&address, "%s,%s", address, temp_buffer);
129                 }
131                 result = error_scan (input_buffer);
132                 if (result != STATE_OK) {
133                         output = strdup (1 + index (input_buffer, ':'));
134                         strip (output);
135                         break;
136                 }
138         }
140         /* scan stderr */
141         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
142                 if (error_scan (input_buffer) != STATE_OK) {
143                         result = max_state (result, error_scan (input_buffer));
144                         output = strdup (1 + index (input_buffer, ':'));
145                         strip (output);
146                 }
147         }
149         /* close stderr */
150         (void) fclose (child_stderr);
152         /* close stdout */
153         if (spclose (child_process)) {
154                 result = max_state (result, STATE_WARNING);
155                 if (!strcmp (output, ""))
156                         output = strdup (_("nslookup returned error status"));
157         }
159         /* If we got here, we should have an address string, 
160                  and we can segfault if we do not */
161         if (address==NULL || strlen(address)==0)
162                 die (STATE_CRITICAL,
163                                                          _("DNS CRITICAL - '%s' output parsing exited with no address\n"),
164                                                          NSLOOKUP_COMMAND);
166         /* compare to expected address */
167         if (result == STATE_OK && match_expected_address && strcmp(address, expected_address)) {
168                 result = STATE_CRITICAL;
169                 asprintf(&output, _("expected %s but got %s"), expected_address, address);
170         }
172         microsec = deltime (tv);
173         elapsed_time = (double)microsec / 1.0e6;
175         if (result == STATE_OK) {
176                 if (strchr (address, ',') == NULL)
177                         multi_address = FALSE;
178                 else
179                         multi_address = TRUE;
181                 printf ("%s %s: ", _("DNS"), _("OK"));
182                 printf (ngettext("%.3f second response time, ", "%.3f seconds response time, ", elapsed_time), elapsed_time);
183                 printf (_("%s returns %s"), query_address, address);
184                 printf ("|%s\n", perfdata ("time", microsec, "us", FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
185         }
186         else if (result == STATE_WARNING)
187                 printf (_("DNS WARNING - %s\n"),
188                                                 !strcmp (output, "") ? _(" Probably a non-existent host/domain") : output);
189         else if (result == STATE_CRITICAL)
190                 printf (_("DNS CRITICAL - %s\n"),
191                                                 !strcmp (output, "") ? _(" Probably a non-existent host/domain") : output);
192         else
193                 printf (_("DNS problem - %s\n"),
194                                                 !strcmp (output, "") ? _(" Probably a non-existent host/domain") : output);
196         return result;
199 int
200 error_scan (char *input_buffer)
203         /* the DNS lookup timed out */
204         if (strstr (input_buffer,       "Note:  nslookup is deprecated and may be removed from future releases.") ||
205             strstr (input_buffer, "Consider using the `dig' or `host' programs instead.  Run nslookup with") ||
206             strstr (input_buffer, "the `-sil[ent]' option to prevent this message from appearing."))
207                 return STATE_OK;
209         /* DNS server is not running... */
210         else if (strstr (input_buffer, "No response from server"))
211                 die (STATE_CRITICAL, _("No response from name server %s\n"), dns_server);
213         /* Host name is valid, but server doesn't have records... */
214         else if (strstr (input_buffer, "No records"))
215                 die (STATE_CRITICAL, _("Name server %s has no records\n"), dns_server);
217         /* Connection was refused */
218         else if (strstr (input_buffer, "Connection refused") ||
219                  (strstr (input_buffer, "** server can't find") &&
220                   strstr (input_buffer, ": REFUSED")) ||
221                  (strstr (input_buffer, "Refused")))
222                 die (STATE_CRITICAL, _("Connection to name server %s was refused\n"), dns_server);
224         /* Host or domain name does not exist */
225         else if (strstr (input_buffer, "Non-existent") ||
226                  strstr (input_buffer, "** server can't find") ||
227                  strstr (input_buffer,"NXDOMAIN"))
228                 die (STATE_CRITICAL, _("Domain %s was not found by the server\n"), query_address);
230         /* Network is unreachable */
231         else if (strstr (input_buffer, "Network is unreachable"))
232                 die (STATE_CRITICAL, _("Network is unreachable\n"));
234         /* Internal server failure */
235         else if (strstr (input_buffer, "Server failure"))
236                 die (STATE_CRITICAL, _("Server failure for %s\n"), dns_server);
238         /* Request error or the DNS lookup timed out */
239         else if (strstr (input_buffer, "Format error") ||
240                  strstr (input_buffer, "Timed out"))
241                 return STATE_WARNING;
243         return STATE_OK;
247 /* process command-line arguments */
248 int
249 process_arguments (int argc, char **argv)
251         int c;
253         int opt_index = 0;
254         static struct option long_opts[] = {
255                 {"help", no_argument, 0, 'h'},
256                 {"version", no_argument, 0, 'V'},
257                 {"verbose", no_argument, 0, 'v'},
258                 {"timeout", required_argument, 0, 't'},
259                 {"hostname", required_argument, 0, 'H'},
260                 {"server", required_argument, 0, 's'},
261                 {"reverse-server", required_argument, 0, 'r'},
262                 {"expected-address", required_argument, 0, 'a'},
263                 {0, 0, 0, 0}
264         };
266         if (argc < 2)
267                 return ERROR;
269         for (c = 1; c < argc; c++)
270                 if (strcmp ("-to", argv[c]) == 0)
271                         strcpy (argv[c], "-t");
273         while (1) {
274                 c = getopt_long (argc, argv, "hVvt:H:s:r:a:", long_opts, &opt_index);
276                 if (c == -1 || c == EOF)
277                         break;
279                 switch (c) {
280                 case '?': /* args not parsable */
281                         printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
282                         print_usage ();
283                         exit (STATE_UNKNOWN);
284                 case 'h': /* help */
285                         print_help ();
286                         exit (STATE_OK);
287                 case 'V': /* version */
288                         print_revision (progname, revision);
289                         exit (STATE_OK);
290                 case 'v': /* version */
291                         verbose = TRUE;
292                         break;
293                 case 't': /* timeout period */
294                         timeout_interval = atoi (optarg);
295                         break;
296                 case 'H': /* hostname */
297                         if (strlen (optarg) >= ADDRESS_LENGTH)
298                                 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
299                         strcpy (query_address, optarg);
300                         break;
301                 case 's': /* server name */
302                         /* TODO: this is_host check is probably unnecessary. Better to confirm nslookup
303                            response matches */
304                         if (is_host (optarg) == FALSE) {
305                                 printf (_("Invalid server name/address\n\n"));
306                                 print_usage ();
307                                 exit (STATE_UNKNOWN);
308                         }
309                         if (strlen (optarg) >= ADDRESS_LENGTH)
310                                 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
311                         strcpy (dns_server, optarg);
312                         break;
313                 case 'r': /* reverse server name */
314                         /* TODO: Is this is_host necessary? */
315                         if (is_host (optarg) == FALSE) {
316                                 printf (_("Invalid host name/address\n\n"));
317                                 print_usage ();
318                                 exit (STATE_UNKNOWN);
319                         }
320                         if (strlen (optarg) >= ADDRESS_LENGTH)
321                                 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
322                         strcpy (ptr_server, optarg);
323                         break;
324                 case 'a': /* expected address */
325                         if (strlen (optarg) >= ADDRESS_LENGTH)
326                                 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
327                         strcpy (expected_address, optarg);
328                         match_expected_address = TRUE;
329                         break;
330                 }
331         }
333         c = optind;
334         if (strlen(query_address)==0 && c<argc) {
335                 if (strlen(argv[c])>=ADDRESS_LENGTH)
336                         die (STATE_UNKNOWN, _("Input buffer overflow\n"));
337                 strcpy (query_address, argv[c++]);
338         }
340         if (strlen(dns_server)==0 && c<argc) {
341                 /* TODO: See -s option */
342                 if (is_host(argv[c]) == FALSE) {
343                         printf (_("Invalid name/address: %s\n\n"), argv[c]);
344                         return ERROR;
345                 }
346                 if (strlen(argv[c]) >= ADDRESS_LENGTH)
347                         die (STATE_UNKNOWN, _("Input buffer overflow\n"));
348                 strcpy (dns_server, argv[c++]);
349         }
351         return validate_arguments ();
354 int
355 validate_arguments ()
357         if (query_address[0] == 0)
358                 return ERROR;
359         else
360                 return OK;
367 \f
368 void
369 print_help (void)
371         print_revision (progname, revision);
373         printf (_("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"));
374         printf (_(COPYRIGHT), copyright, email);
376         print_usage ();
378         printf (_(UT_HELP_VRSN));
380         printf (_("\
381 -H, --hostname=HOST\n\
382    The name or address you want to query\n\
383 -s, --server=HOST\n\
384    Optional DNS server you want to use for the lookup\n\
385 -a, --expected-address=IP-ADDRESS\n\
386    Optional IP address you expect the DNS server to return\n"));
388         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
390         printf (_("\n\
391 This plugin uses the nslookup program to obtain the IP address\n\
392 for the given host/domain query.  A optional DNS server to use may\n\
393 be specified.  If no DNS server is specified, the default server(s)\n\
394 specified in /etc/resolv.conf will be used.\n"));
396         printf (_(UT_SUPPORT));
402 void
403 print_usage (void)
405         printf (_("\
406 Usage: %s -H host [-s server] [-a expected-address] [-t timeout]\n\
407        %s --help\n\
408        %s --version\n"),
409                                         progname, progname, progname);