Code

cleanup process_arguments, print_help, and print_usage
[nagiosplug.git] / plugins / check_dns.c
1 /******************************************************************************
2  *
3  * CHECK_DNS.C
4  *
5  * Program: DNS plugin for Nagios
6  * License: GPL
7  * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
8  *
9  * Last Modified: $Date$
10  *
11  * Notes:
12  *  - Safe popen added by Karl DeBisschop 9-11-99
13  *  - expected-address parameter added by Alex Chaffee - 7 Oct 2002
14  *
15  * Command line: (see print_usage)
16  *
17  * Description:
18  *
19  * This program will use the nslookup program to obtain the IP address
20  * for a given host name.  A optional DNS server may be specified.  If
21  * no DNS server is specified, the default server(s) for the system
22  * are used.
23  *
24  * Return Values:
25  *  OK           The DNS query was successful (host IP address was returned).
26  *  WARNING      The DNS server responded, but could not fulfill the request.
27  *  CRITICAL     The DNS server is not responding or encountered an error.
28  *
29  * License Information:
30  *
31  * This program is free software; you can redistribute it and/or modify
32  * it under the terms of the GNU General Public License as published by
33  * the Free Software Foundation; either version 2 of the License, or
34  * (at your option) any later version.
35  *
36  * This program is distributed in the hope that it will be useful,
37  * but WITHOUT ANY WARRANTY; without even the implied warranty of
38  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
39  * GNU General Public License for more details.
40  *
41  * You should have received a copy of the GNU General Public License
42  * along with this program; if not, write to the Free Software
43  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
44  *
45  *****************************************************************************/
47 #include "common.h"
48 #include "popen.h"
49 #include "utils.h"
51 int process_arguments (int, char **);
52 int call_getopt (int, char **);
53 int validate_arguments (void);
54 void print_usage (char *);
55 void print_help (char *);
56 int error_scan (char *);
58 #define ADDRESS_LENGTH 256
59 char query_address[ADDRESS_LENGTH] = "";
60 char dns_server[ADDRESS_LENGTH] = "";
61 char ptr_server[ADDRESS_LENGTH] = "";
62 int verbose = FALSE;
63 char expected_address[ADDRESS_LENGTH] = "";
64 int match_expected_address = FALSE;
66 int
67 main (int argc, char **argv)
68 {
69         char *command_line = NULL;
70         char input_buffer[MAX_INPUT_BUFFER];
71         char *output = NULL;
72         char *address = NULL;
73         char *temp_buffer = NULL;
74         int result = STATE_UNKNOWN;
76         /* Set signal handling and alarm */
77         if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
78                 printf ("Cannot catch SIGALRM");
79                 return STATE_UNKNOWN;
80         }
82         if (process_arguments (argc, argv) != OK) {
83                 print_usage (my_basename (argv[0]));
84                 return STATE_UNKNOWN;
85         }
87         /* get the command to run */
88         command_line = ssprintf (command_line, "%s %s %s", NSLOOKUP_COMMAND,
89                 query_address, dns_server);
91         alarm (timeout_interval);
92         time (&start_time);
94         if (verbose)
95                 printf ("%s\n", command_line);
96         /* run the command */
97         child_process = spopen (command_line);
98         if (child_process == NULL) {
99                 printf ("Could not open pipe: %s\n", command_line);
100                 return STATE_UNKNOWN;
101         }
103         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
104         if (child_stderr == NULL)
105                 printf ("Could not open stderr for %s\n", command_line);
107         /* scan stdout */
108         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
110                 if (verbose)
111                         printf ("%s\n", input_buffer);
113                 if (strstr (input_buffer, ".in-addr.arpa")) {
114                         if ((temp_buffer = strstr (input_buffer, "name = ")))
115                                 address = strscpy (address, temp_buffer + 7);
116                         else {
117                                 output = strscpy (output, "Unknown error (plugin)");
118                                 result = STATE_WARNING;
119                         }
120                 }
122                 /* the server is responding, we just got the host name... */
123                 if (strstr (input_buffer, "Name:")) {
125                         /* get the host address */
126                         if (!fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
127                                 break;
129                         if (verbose)
130                                 printf ("%s\n", input_buffer);
132                         if ((temp_buffer = index (input_buffer, ':'))) {
133                                 address = strscpy (address, temp_buffer + 2);
134                                 strip (address);
135                                 result = STATE_OK;
136                         }
137                         else {
138                                 output = strscpy (output, "Unknown error (plugin)");
139                                 result = STATE_WARNING;
140                         }
142                         break;
143                 }
145                 result = error_scan (input_buffer);
146                 if (result != STATE_OK) {
147                         output = strscpy (output, 1 + index (input_buffer, ':'));
148                         break;
149                 }
151         }
153         /* scan stderr */
154         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
155                 if (error_scan (input_buffer) != STATE_OK) {
156                         result = max_state (result, error_scan (input_buffer));
157                         output = strscpy (output, 1 + index (input_buffer, ':'));
158                 }
159         }
161         /* close stderr */
162         (void) fclose (child_stderr);
164         /* close stdout */
165         if (spclose (child_process)) {
166                 result = max_state (result, STATE_WARNING);
167                 if (!strcmp (output, ""))
168                         output = strscpy (output, "nslookup returned error status");
169         }
171         /* compare to expected address */
172         if (result == STATE_OK && match_expected_address && strcmp(address, expected_address)) {
173                 result = STATE_CRITICAL;
174                 output = ssprintf(output, "expected %s but got %s", expected_address, address);
175                 }
176         
177         (void) time (&end_time);
179         if (result == STATE_OK)
180                 printf ("DNS ok - %d seconds response time, Address(es) is/are %s\n",
181                                                 (int) (end_time - start_time), address);
182         else if (result == STATE_WARNING)
183                 printf ("DNS WARNING - %s\n",
184                         !strcmp (output, "") ? " Probably a non-existent host/domain" : output);
185         else if (result == STATE_CRITICAL)
186                 printf ("DNS CRITICAL - %s\n",
187                         !strcmp (output, "") ? " Probably a non-existent host/domain" : output);
188         else
189                 printf ("DNS problem - %s\n",
190                         !strcmp (output, "") ? " Probably a non-existent host/domain" : output);
192         return result;
195 int
196 error_scan (char *input_buffer)
199         /* the DNS lookup timed out */
200         if (strstr (input_buffer,
201              "Note:  nslookup is deprecated and may be removed from future releases.")
202             || strstr (input_buffer,
203              "Consider using the `dig' or `host' programs instead.  Run nslookup with")
204             || strstr (input_buffer,
205              "the `-sil[ent]' option to prevent this message from appearing."))
206                 return STATE_OK;
208         /* the DNS lookup timed out */
209         else if (strstr (input_buffer, "Timed out"))
210                 return STATE_WARNING;
212         /* DNS server is not running... */
213         else if (strstr (input_buffer, "No response from server"))
214                 return STATE_CRITICAL;
216         /* Host name is valid, but server doesn't have records... */
217         else if (strstr (input_buffer, "No records"))
218                 return STATE_WARNING;
220         /* Host or domain name does not exist */
221         else if (strstr (input_buffer, "Non-existent"))
222                 return STATE_CRITICAL;
223         else if (strstr (input_buffer, "** server can't find"))
224                 return STATE_CRITICAL;
225         else if(strstr(input_buffer,"NXDOMAIN")) /* 9.x */
226                 return STATE_CRITICAL;
228         /* Connection was refused */
229         else if (strstr (input_buffer, "Connection refused"))
230                 return STATE_CRITICAL;
232         /* Network is unreachable */
233         else if (strstr (input_buffer, "Network is unreachable"))
234                 return STATE_CRITICAL;
236         /* Internal server failure */
237         else if (strstr (input_buffer, "Server failure"))
238                 return STATE_CRITICAL;
240         /* DNS server refused to service request */
241         else if (strstr (input_buffer, "Refused"))
242                 return STATE_CRITICAL;
244         /* Request error */
245         else if (strstr (input_buffer, "Format error"))
246                 return STATE_WARNING;
248         else
249                 return STATE_OK;
253 /* process command-line arguments */
254 int
255 process_arguments (int argc, char **argv)
257         int c;
259         if (argc < 2)
260                 return ERROR;
262         for (c = 1; c < argc; c++)
263                 if (strcmp ("-to", argv[c]) == 0)
264                         strcpy (argv[c], "-t");
266         c = 0;
267         while (c += (call_getopt (argc - c, &argv[c]))) {
268                 if (argc <= c)
269                         break;
270                 if (query_address[0] == 0) {
271                         if (is_host (argv[c]) == FALSE) {
272                                 printf ("Invalid name/address: %s\n\n", argv[c]);
273                                 return ERROR;
274                         }
275                         if (strlen (argv[c]) >= ADDRESS_LENGTH)
276                                 terminate (STATE_UNKNOWN, "Input buffer overflow\n");
277                         strcpy (query_address, argv[c]);
278                 }
279                 else if (dns_server[0] == 0) {
280                         if (is_host (argv[c]) == FALSE) {
281                                 printf ("Invalid name/address: %s\n\n", argv[c]);
282                                 return ERROR;
283                         }
284                         if (strlen (argv[c]) >= ADDRESS_LENGTH)
285                                 terminate (STATE_UNKNOWN, "Input buffer overflow\n");
286                         strcpy (dns_server, argv[c]);
287                 }
288         }
290         return validate_arguments ();
294 int
295 call_getopt (int argc, char **argv)
297         int c, i = 1;
299 #ifdef HAVE_GETOPT_H
300         int opt_index = 0;
301         static struct option long_opts[] = {
302                 {"help", no_argument, 0, 'h'},
303                 {"version", no_argument, 0, 'V'},
304                 {"verbose", no_argument, 0, 'v'},
305                 {"timeout", required_argument, 0, 't'},
306                 {"hostname", required_argument, 0, 'H'},
307                 {"server", required_argument, 0, 's'},
308                 {"reverse-server", required_argument, 0, 'r'},
309                 {"expected-address", required_argument, 0, 'a'},
310                 {0, 0, 0, 0}
311         };
312 #endif
315         while (1) {
316 #ifdef HAVE_GETOPT_H
317                 c = getopt_long (argc, argv, "+?hVvt:H:s:r:a:", long_opts, &opt_index);
318 #else
319                 c = getopt (argc, argv, "+?hVvt:H:s:r:a:");
320 #endif
322                 if (c == -1 || c == EOF)
323                         break;
325                 i++;
326                 switch (c) {
327                 case 't':
328                 case 'H':
329                 case 's':
330                 case 'r':
331                 case 'a':
332                         i++;
333                 }
335                 switch (c) {
336                 case '?': /* args not parsable */
337                         printf ("%s: Unknown argument: %s\n\n", my_basename (argv[0]), optarg);
338                         print_usage (my_basename (argv[0]));
339                         exit (STATE_UNKNOWN);
340                 case 'h': /* help */
341                         print_help (my_basename (argv[0]));
342                         exit (STATE_OK);
343                 case 'V': /* version */
344                         print_revision (my_basename (argv[0]), "$Revision$");
345                         exit (STATE_OK);
346                 case 'v': /* version */
347                         verbose = TRUE;
348                         break;
349                 case 't': /* timeout period */
350                         timeout_interval = atoi (optarg);
351                         break;
352                 case 'H': /* hostname */
353                         if (is_host (optarg) == FALSE) {
354                                 printf ("Invalid host name/address\n\n");
355                                 print_usage (my_basename (argv[0]));
356                                 exit (STATE_UNKNOWN);
357                         }
358                         if (strlen (optarg) >= ADDRESS_LENGTH)
359                                 terminate (STATE_UNKNOWN, "Input buffer overflow\n");
360                         strcpy (query_address, optarg);
361                         break;
362                 case 's': /* server name */
363                         if (is_host (optarg) == FALSE) {
364                                 printf ("Invalid server name/address\n\n");
365                                 print_usage (my_basename (argv[0]));
366                                 exit (STATE_UNKNOWN);
367                         }
368                         if (strlen (optarg) >= ADDRESS_LENGTH)
369                                 terminate (STATE_UNKNOWN, "Input buffer overflow\n");
370                         strcpy (dns_server, optarg);
371                         break;
372                 case 'r': /* reverse server name */
373                         if (is_host (optarg) == FALSE) {
374                                 printf ("Invalid host name/address\n\n");
375                                 print_usage (my_basename (argv[0]));
376                                 exit (STATE_UNKNOWN);
377                         }
378                         if (strlen (optarg) >= ADDRESS_LENGTH)
379                                 terminate (STATE_UNKNOWN, "Input buffer overflow\n");
380                         strcpy (ptr_server, optarg);
381                         break;
382                 case 'a': /* expected address */
383                         if (is_dotted_quad (optarg) == FALSE) {
384                                 printf ("Invalid expected address\n\n");
385                                 print_usage (my_basename (argv[0]));
386                                 exit (STATE_UNKNOWN);
387                         }
388                         if (strlen (optarg) >= ADDRESS_LENGTH)
389                                 terminate (STATE_UNKNOWN, "Input buffer overflow\n");
390                         strcpy (expected_address, optarg);
391                         match_expected_address = TRUE;
392                         break;
393                 }
394         }
395         return i;
398 int
399 validate_arguments ()
401         if (query_address[0] == 0)
402                 return ERROR;
403         else
404                 return OK;
407 void
408 print_usage (char *cmd)
410         printf ("Usage: %s -H host [-s server] [-a expected-address] [-t timeout]\n" "       %s --help\n"
411                                         "       %s --version\n", cmd, cmd, cmd);
414 void
415 print_help (char *cmd)
417         print_revision (cmd, "$Revision$");
418         printf ("Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)\n\n");
419         print_usage (cmd);
420         printf ("\n");
421         printf
422                 ("-H, --hostname=HOST\n"
423                  "   The name or address you want to query\n"
424                  "-s, --server=HOST\n"
425                  "   Optional DNS server you want to use for the lookup\n"
426                  "-a, --expected-address=IP-ADDRESS\n"
427                  "   Optional IP address you expect the DNS server to return\n"
428                  "-t, --timeout=INTEGER\n"
429                  "   Seconds before connection times out (default: %d)\n"
430                  "-h, --help\n"
431                  "   Print detailed help\n"
432                  "-V, --version\n"
433                  "   Print version numbers and license information\n"
434                  "\n"
435                  "This plugin uses the nslookup program to obtain the IP address\n"
436                  "for the given host/domain query.  A optional DNS server to use may\n"
437                  "be specified.  If no DNS server is specified, the default server(s)\n"
438                  "specified in /etc/resolv.conf will be used.\n", DEFAULT_SOCKET_TIMEOUT);