aaa3f12d830356dc8dc3884b29cd2031374f4a4b
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 LIMITATION: nslookup on Solaris 7 can return output over 2 lines, which will not
18 be picked up by this plugin
20 $Id$
22 ******************************************************************************/
24 #include "common.h"
25 #include "popen.h"
26 #include "utils.h"
27 #include "netutils.h"
29 const char *progname = "check_dns";
30 const char *revision = "$Revision$";
31 const char *copyright = "2000-2004";
32 const char *email = "nagiosplug-devel@lists.sourceforge.net";
34 int process_arguments (int, char **);
35 int validate_arguments (void);
36 int error_scan (char *);
37 void print_help (void);
38 void print_usage (void);
40 #define ADDRESS_LENGTH 256
41 char query_address[ADDRESS_LENGTH] = "";
42 char dns_server[ADDRESS_LENGTH] = "";
43 char ptr_server[ADDRESS_LENGTH] = "";
44 int verbose = FALSE;
45 char expected_address[ADDRESS_LENGTH] = "";
46 int match_expected_address = FALSE;
47 int expect_authority = FALSE;
49 int
50 main (int argc, char **argv)
51 {
52 char *command_line = NULL;
53 char input_buffer[MAX_INPUT_BUFFER];
54 char *output = NULL;
55 char *address = NULL;
56 char *temp_buffer = NULL;
57 int non_authoritative = FALSE;
58 int result = STATE_UNKNOWN;
59 double elapsed_time;
60 long microsec;
61 struct timeval tv;
62 int multi_address;
63 int parse_address = FALSE; /* This flag scans for Address: but only after Name: */
65 setlocale (LC_ALL, "");
66 bindtextdomain (PACKAGE, LOCALEDIR);
67 textdomain (PACKAGE);
69 /* Set signal handling and alarm */
70 if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
71 usage4 (_("Cannot catch SIGALRM"));
72 }
74 if (process_arguments (argc, argv) != TRUE) {
75 usage4 (_("Could not parse arguments"));
76 }
78 /* get the command to run */
79 asprintf (&command_line, "%s %s %s", NSLOOKUP_COMMAND, query_address, dns_server);
81 alarm (timeout_interval);
82 gettimeofday (&tv, NULL);
84 if (verbose)
85 printf ("%s\n", command_line);
87 /* run the command */
88 child_process = spopen (command_line);
89 if (child_process == NULL) {
90 printf (_("Could not open pipe: %s\n"), command_line);
91 return STATE_UNKNOWN;
92 }
94 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
95 if (child_stderr == NULL)
96 printf (_("Could not open stderr for %s\n"), command_line);
98 /* scan stdout */
99 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
101 if (verbose)
102 printf ("%s", input_buffer);
104 if (strstr (input_buffer, ".in-addr.arpa")) {
105 if ((temp_buffer = strstr (input_buffer, "name = ")))
106 address = strdup (temp_buffer + 7);
107 else {
108 output = strdup (_("Warning plugin error"));
109 result = STATE_WARNING;
110 }
111 }
113 /* the server is responding, we just got the host name... */
114 if (strstr (input_buffer, "Name:"))
115 parse_address = TRUE;
116 else if (parse_address == TRUE && (strstr (input_buffer, "Address:") ||
117 strstr (input_buffer, "Addresses:"))) {
118 temp_buffer = index (input_buffer, ':');
119 temp_buffer++;
121 /* Strip leading spaces */
122 for (; *temp_buffer != '\0' && *temp_buffer == ' '; temp_buffer++)
123 /* NOOP */;
125 strip(temp_buffer);
126 if (temp_buffer==NULL || strlen(temp_buffer)==0) {
127 die (STATE_CRITICAL,
128 _("DNS CRITICAL - '%s' returned empty host name string\n"),
129 NSLOOKUP_COMMAND);
130 }
132 if (address == NULL)
133 address = strdup (temp_buffer);
134 else
135 asprintf(&address, "%s,%s", address, temp_buffer);
136 }
138 else if (strstr (input_buffer, "Non-authoritative answer:")) {
139 non_authoritative = TRUE;
140 }
142 result = error_scan (input_buffer);
143 if (result != STATE_OK) {
144 output = strdup (1 + index (input_buffer, ':'));
145 strip (output);
146 break;
147 }
149 }
151 /* scan stderr */
152 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
153 if (error_scan (input_buffer) != STATE_OK) {
154 result = max_state (result, error_scan (input_buffer));
155 output = strdup (1 + index (input_buffer, ':'));
156 strip (output);
157 }
158 }
160 /* close stderr */
161 (void) fclose (child_stderr);
163 /* close stdout */
164 if (spclose (child_process)) {
165 result = max_state (result, STATE_WARNING);
166 if (!strcmp (output, ""))
167 output = strdup (_("nslookup returned error status"));
168 }
170 /* If we got here, we should have an address string,
171 and we can segfault if we do not */
172 if (address==NULL || strlen(address)==0)
173 die (STATE_CRITICAL,
174 _("DNS CRITICAL - '%s' output parsing exited with no address\n"),
175 NSLOOKUP_COMMAND);
177 /* compare to expected address */
178 if (result == STATE_OK && match_expected_address && strcmp(address, expected_address)) {
179 result = STATE_CRITICAL;
180 asprintf(&output, _("expected %s but got %s"), expected_address, address);
181 }
183 /* check if authoritative */
184 if (result == STATE_OK && expect_authority && non_authoritative) {
185 result = STATE_CRITICAL;
186 asprintf(&output, _("server %s is not authoritative for %s"), dns_server, query_address);
187 }
189 microsec = deltime (tv);
190 elapsed_time = (double)microsec / 1.0e6;
192 if (result == STATE_OK) {
193 if (strchr (address, ',') == NULL)
194 multi_address = FALSE;
195 else
196 multi_address = TRUE;
198 printf ("DNS %s: ", _("OK"));
199 printf (_("%.3f seconds response time"), elapsed_time);
200 printf (_("%s returns %s"), query_address, address);
201 printf ("|%s\n", fperfdata ("time", elapsed_time, "s", FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
202 }
203 else if (result == STATE_WARNING)
204 printf (_("DNS WARNING - %s\n"),
205 !strcmp (output, "") ? _(" Probably a non-existent host/domain") : output);
206 else if (result == STATE_CRITICAL)
207 printf (_("DNS CRITICAL - %s\n"),
208 !strcmp (output, "") ? _(" Probably a non-existent host/domain") : output);
209 else
210 printf (_("DNS UNKNOW - %s\n"),
211 !strcmp (output, "") ? _(" Probably a non-existent host/domain") : output);
213 return result;
214 }
218 int
219 error_scan (char *input_buffer)
220 {
222 /* the DNS lookup timed out */
223 if (strstr (input_buffer, "Note: nslookup is deprecated and may be removed from future releases.") ||
224 strstr (input_buffer, "Consider using the `dig' or `host' programs instead. Run nslookup with") ||
225 strstr (input_buffer, "the `-sil[ent]' option to prevent this message from appearing."))
226 return STATE_OK;
228 /* DNS server is not running... */
229 else if (strstr (input_buffer, "No response from server"))
230 die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
232 /* Host name is valid, but server doesn't have records... */
233 else if (strstr (input_buffer, "No records"))
234 die (STATE_CRITICAL, _("DNS %s has no records\n"), dns_server);
236 /* Connection was refused */
237 else if (strstr (input_buffer, "Connection refused") ||
238 strstr (input_buffer, "Refused") ||
239 (strstr (input_buffer, "** server can't find") &&
240 strstr (input_buffer, ": REFUSED")))
241 die (STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server);
243 /* Host or domain name does not exist */
244 else if (strstr (input_buffer, "Non-existent") ||
245 strstr (input_buffer, "** server can't find") ||
246 strstr (input_buffer,"NXDOMAIN"))
247 die (STATE_CRITICAL, _("Domain %s was not found by the server\n"), query_address);
249 /* Network is unreachable */
250 else if (strstr (input_buffer, "Network is unreachable"))
251 die (STATE_CRITICAL, _("Network is unreachable\n"));
253 /* Internal server failure */
254 else if (strstr (input_buffer, "Server failure"))
255 die (STATE_CRITICAL, _("DNS failure for %s\n"), dns_server);
257 /* Request error or the DNS lookup timed out */
258 else if (strstr (input_buffer, "Format error") ||
259 strstr (input_buffer, "Timed out"))
260 return STATE_WARNING;
262 return STATE_OK;
264 }
268 /* process command-line arguments */
269 int
270 process_arguments (int argc, char **argv)
271 {
272 int c;
274 int opt_index = 0;
275 static struct option long_opts[] = {
276 {"help", no_argument, 0, 'h'},
277 {"version", no_argument, 0, 'V'},
278 {"verbose", no_argument, 0, 'v'},
279 {"timeout", required_argument, 0, 't'},
280 {"hostname", required_argument, 0, 'H'},
281 {"server", required_argument, 0, 's'},
282 {"reverse-server", required_argument, 0, 'r'},
283 {"expected-address", required_argument, 0, 'a'},
284 {"expect-authority", no_argument, 0, 'A'},
285 {0, 0, 0, 0}
286 };
288 if (argc < 2)
289 return ERROR;
291 for (c = 1; c < argc; c++)
292 if (strcmp ("-to", argv[c]) == 0)
293 strcpy (argv[c], "-t");
295 while (1) {
296 c = getopt_long (argc, argv, "hVvAt:H:s:r:a:", long_opts, &opt_index);
298 if (c == -1 || c == EOF)
299 break;
301 switch (c) {
302 case '?': /* args not parsable */
303 printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
304 print_usage ();
305 exit (STATE_UNKNOWN);
306 case 'h': /* help */
307 print_help ();
308 exit (STATE_OK);
309 case 'V': /* version */
310 print_revision (progname, revision);
311 exit (STATE_OK);
312 case 'v': /* version */
313 verbose = TRUE;
314 break;
315 case 't': /* timeout period */
316 timeout_interval = atoi (optarg);
317 break;
318 case 'H': /* hostname */
319 if (strlen (optarg) >= ADDRESS_LENGTH)
320 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
321 strcpy (query_address, optarg);
322 break;
323 case 's': /* server name */
324 /* TODO: this is_host check is probably unnecessary. */
325 /* Better to confirm nslookup response matches */
326 if (is_host (optarg) == FALSE) {
327 printf (_("Invalid hostname/address\n\n"));
328 print_usage ();
329 exit (STATE_UNKNOWN);
330 }
331 if (strlen (optarg) >= ADDRESS_LENGTH)
332 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
333 strcpy (dns_server, optarg);
334 break;
335 case 'r': /* reverse server name */
336 /* TODO: Is this is_host necessary? */
337 if (is_host (optarg) == FALSE) {
338 usage2 (_("Invalid hostname/address"), optarg);
339 }
340 if (strlen (optarg) >= ADDRESS_LENGTH)
341 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
342 strcpy (ptr_server, optarg);
343 break;
344 case 'a': /* expected address */
345 if (strlen (optarg) >= ADDRESS_LENGTH)
346 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
347 strcpy (expected_address, optarg);
348 match_expected_address = TRUE;
349 break;
350 case 'A': /* expect authority */
351 expect_authority = TRUE;
352 break;
353 }
354 }
356 c = optind;
357 if (strlen(query_address)==0 && c<argc) {
358 if (strlen(argv[c])>=ADDRESS_LENGTH)
359 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
360 strcpy (query_address, argv[c++]);
361 }
363 if (strlen(dns_server)==0 && c<argc) {
364 /* TODO: See -s option */
365 if (is_host(argv[c]) == FALSE) {
366 printf (_("Invalid hostname/address: %s\n\n"), argv[c]);
367 return ERROR;
368 }
369 if (strlen(argv[c]) >= ADDRESS_LENGTH)
370 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
371 strcpy (dns_server, argv[c++]);
372 }
374 return validate_arguments ();
375 }
379 int
380 validate_arguments ()
381 {
382 if (query_address[0] == 0)
383 return ERROR;
384 else
385 return OK;
386 }
390 void
391 print_help (void)
392 {
393 print_revision (progname, revision);
395 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
396 printf (COPYRIGHT, copyright, email);
398 print_usage ();
400 printf (_(UT_HELP_VRSN));
402 printf (_("\
403 -H, --hostname=HOST\n\
404 The name or address you want to query\n\
405 -s, --server=HOST\n\
406 Optional DNS server you want to use for the lookup\n\
407 -a, --expected-address=IP-ADDRESS\n\
408 Optional IP address you expect the DNS server to return\n\
409 -A, --expect-authority\n\
410 Optionally expect the DNS server to be authoritative for the lookup\n"));
412 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
414 printf (_("\n\
415 This plugin uses the nslookup program to obtain the IP address\n\
416 for the given host/domain query. A optional DNS server to use may\n\
417 be specified. If no DNS server is specified, the default server(s)\n\
418 specified in /etc/resolv.conf will be used.\n"));
420 printf (_(UT_SUPPORT));
421 }
425 void
426 print_usage (void)
427 {
428 printf (_("\
429 Usage: %s -H host [-s server] [-a expected-address] [-A] [-t timeout]\n\
430 %s --help\n\
431 %s --version\n"), progname, progname, progname);
432 }