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 $Id$
19 *****************************************************************************/
21 const char *progname = "check_dig";
22 const char *revision = "$Revision$";
23 const char *copyright = "2002-2004";
24 const char *email = "nagiosplug-devel@lists.sourceforge.net";
26 #include "common.h"
27 #include "netutils.h"
28 #include "utils.h"
29 #include "popen.h"
31 int process_arguments (int, char **);
32 int validate_arguments (void);
33 void print_help (void);
34 void print_usage (void);
36 enum {
37 UNDEFINED = 0,
38 DEFAULT_PORT = 53
39 };
41 char *query_address = NULL;
42 char *record_type = "A";
43 char *expected_address = NULL;
44 char *dns_server = NULL;
45 int verbose = FALSE;
46 int server_port = DEFAULT_PORT;
47 double warning_interval = UNDEFINED;
48 double critical_interval = UNDEFINED;
49 struct timeval tv;
51 int
52 main (int argc, char **argv)
53 {
54 char input_buffer[MAX_INPUT_BUFFER];
55 char *command_line;
56 char *output;
57 char *t;
58 long microsec;
59 double elapsed_time;
60 int result = STATE_UNKNOWN;
62 output = strdup ("");
64 setlocale (LC_ALL, "");
65 bindtextdomain (PACKAGE, LOCALEDIR);
66 textdomain (PACKAGE);
68 /* Set signal handling and alarm */
69 if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR)
70 usage4 (_("Cannot catch SIGALRM"));
72 if (process_arguments (argc, argv) == ERROR)
73 usage4 (_("Could not parse arguments"));
75 /* get the command to run */
76 asprintf (&command_line, "%s @%s -p %d %s -t %s",
77 PATH_TO_DIG, dns_server, server_port, query_address, record_type);
79 alarm (timeout_interval);
80 gettimeofday (&tv, NULL);
82 if (verbose) {
83 printf ("%s\n", command_line);
84 if(expected_address != NULL) {
85 printf (_("Looking for: '%s'\n"), expected_address);
86 } else {
87 printf (_("Looking for: '%s'\n"), query_address);
88 }
89 }
91 /* run the command */
92 child_process = spopen (command_line);
93 if (child_process == NULL) {
94 printf (_("Could not open pipe: %s\n"), command_line);
95 return STATE_UNKNOWN;
96 }
98 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
99 if (child_stderr == NULL)
100 printf (_("Could not open stderr for %s\n"), command_line);
102 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
104 /* the server is responding, we just got the host name... */
105 if (strstr (input_buffer, ";; ANSWER SECTION:")) {
107 /* loop through the whole 'ANSWER SECTION' */
108 do {
109 /* get the host address */
110 if (!fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
111 break;
113 if (strpbrk (input_buffer, "\r\n"))
114 input_buffer[strcspn (input_buffer, "\r\n")] = '\0';
116 if (verbose && !strstr (input_buffer, ";; "))
117 printf ("%s\n", input_buffer);
119 if (expected_address==NULL && strstr (input_buffer, query_address) != NULL) {
120 output = strdup(input_buffer);
121 result = STATE_OK;
122 }
123 else if (expected_address != NULL && strstr (input_buffer, expected_address) != NULL) {
124 output = strdup(input_buffer);
125 result = STATE_OK;
126 }
128 /* Translate output TAB -> SPACE */
129 t = output;
130 while ((t = index(t, '\t')) != NULL)
131 *t = ' ';
133 } while (!strstr (input_buffer, ";; "));
135 if (result == STATE_UNKNOWN) {
136 asprintf (&output, _("Server not found in ANSWER SECTION"));
137 result = STATE_WARNING;
138 }
139 }
141 }
143 if (result == STATE_UNKNOWN) {
144 asprintf (&output, _("No ANSWER SECTION found"));
145 }
147 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
148 /* If we get anything on STDERR, at least set warning */
149 result = max_state (result, STATE_WARNING);
150 printf ("%s", input_buffer);
151 if (strlen (output) == 0)
152 output = strdup (1 + index (input_buffer, ':'));
153 }
155 (void) fclose (child_stderr);
157 /* close the pipe */
158 if (spclose (child_process)) {
159 result = max_state (result, STATE_WARNING);
160 if (strlen (output) == 0)
161 asprintf (&output, _("dig returned an error status"));
162 }
164 microsec = deltime (tv);
165 elapsed_time = (double)microsec / 1.0e6;
167 if (output == NULL || strlen (output) == 0)
168 asprintf (&output, _(" Probably a non-existent host/domain"));
170 if (critical_interval > UNDEFINED && elapsed_time > critical_interval)
171 result = STATE_CRITICAL;
173 else if (warning_interval > UNDEFINED && elapsed_time > warning_interval)
174 result = STATE_WARNING;
176 asprintf (&output, _("%.3f seconds response time (%s)"), elapsed_time, output);
178 printf ("DNS %s - %s|%s\n",
179 state_text (result), output,
180 fperfdata("time", elapsed_time, "s",
181 (warning_interval>UNDEFINED?TRUE:FALSE),
182 warning_interval,
183 (critical_interval>UNDEFINED?TRUE:FALSE),
184 critical_interval,
185 TRUE, 0, FALSE, 0));
186 return result;
187 }
191 /* process command-line arguments */
192 int
193 process_arguments (int argc, char **argv)
194 {
195 int c;
197 int option = 0;
198 static struct option longopts[] = {
199 {"hostname", required_argument, 0, 'H'},
200 {"query_address", required_argument, 0, 'l'},
201 {"warning", required_argument, 0, 'w'},
202 {"critical", required_argument, 0, 'c'},
203 {"timeout", required_argument, 0, 't'},
204 {"verbose", no_argument, 0, 'v'},
205 {"version", no_argument, 0, 'V'},
206 {"help", no_argument, 0, 'h'},
207 {"record_type", required_argument, 0, 'T'},
208 {"expected_address", required_argument, 0, 'a'},
209 {0, 0, 0, 0}
210 };
212 if (argc < 2)
213 return ERROR;
215 while (1) {
216 c = getopt_long (argc, argv, "hVvt:l:H:w:c:T:a:", longopts, &option);
218 if (c == -1 || c == EOF)
219 break;
221 switch (c) {
222 case '?': /* help */
223 usage2 (_("Unknown argument"), optarg);
224 case 'h': /* help */
225 print_help ();
226 exit (STATE_OK);
227 case 'V': /* version */
228 print_revision (progname, revision);
229 exit (STATE_OK);
230 case 'H': /* hostname */
231 if (is_host (optarg)) {
232 dns_server = optarg;
233 }
234 else {
235 usage2 (_("Invalid hostname/address"), optarg);
236 }
237 break;
238 case 'p': /* server port */
239 if (is_intpos (optarg)) {
240 server_port = atoi (optarg);
241 }
242 else {
243 usage2 (_("Port must be a positive integer"), optarg);
244 }
245 break;
246 case 'l': /* address to lookup */
247 query_address = optarg;
248 break;
249 case 'w': /* warning */
250 if (is_nonnegative (optarg)) {
251 warning_interval = strtod (optarg, NULL);
252 }
253 else {
254 usage2 (_("Warning interval must be a positive integer"), optarg);
255 }
256 break;
257 case 'c': /* critical */
258 if (is_nonnegative (optarg)) {
259 critical_interval = strtod (optarg, NULL);
260 }
261 else {
262 usage2 (_("Critical interval must be a positive integer"), optarg);
263 }
264 break;
265 case 't': /* timeout */
266 if (is_intnonneg (optarg)) {
267 timeout_interval = atoi (optarg);
268 }
269 else {
270 usage2 (_("Timeout interval must be a positive integer"), optarg);
271 }
272 break;
273 case 'v': /* verbose */
274 verbose = TRUE;
275 break;
276 case 'T':
277 record_type = optarg;
278 break;
279 case 'a':
280 expected_address = optarg;
281 break;
282 }
283 }
285 c = optind;
286 if (dns_server == NULL) {
287 if (c < argc) {
288 if (is_host (argv[c])) {
289 dns_server = argv[c];
290 }
291 else {
292 usage2 (_("Invalid hostname/address"), argv[c]);
293 }
294 }
295 else {
296 dns_server = strdup ("127.0.0.1");
297 }
298 }
300 return validate_arguments ();
301 }
305 int
306 validate_arguments (void)
307 {
308 return OK;
309 }
313 void
314 print_help (void)
315 {
316 char *myport;
318 asprintf (&myport, "%d", DEFAULT_PORT);
320 print_revision (progname, revision);
322 printf ("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
323 printf (COPYRIGHT, copyright, email);
325 printf (_("Test the DNS service on the specified host using dig\n\n"));
327 print_usage ();
329 printf (_(UT_HELP_VRSN));
331 printf (_(UT_HOST_PORT), 'P', myport);
333 printf (_("\
334 -l, --lookup=STRING\n\
335 machine name to lookup\n"));
337 printf (_("\
338 -T, --record_type=STRING\n\
339 record type to lookup (default: A)\n"));
341 printf (_("\
342 -a, --expected_address=STRING\n\
343 an address expected to be in the answer section.\n\
344 if not set, uses whatever was in -l\n"));
346 printf (_(UT_WARN_CRIT));
348 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
350 printf (_(UT_VERBOSE));
352 printf (_(UT_SUPPORT));
353 }
357 void
358 print_usage (void)
359 {
360 printf ("\
361 Usage: %s -H host -l lookup [-p <server port>] [-T <query type>]\n\
362 [-w <warning interval>] [-c <critical interval>] [-t <timeout>]\n\
363 [-a <expected answer address>] [-v]\n", progname);
364 }