diff options
Diffstat (limited to 'plugins/check_tcp.c')
-rw-r--r-- | plugins/check_tcp.c | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/plugins/check_tcp.c b/plugins/check_tcp.c new file mode 100644 index 00000000..bef0e752 --- /dev/null +++ b/plugins/check_tcp.c | |||
@@ -0,0 +1,563 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is part of the Nagios Plugins. | ||
4 | * | ||
5 | * Copyright (c) 1999 Ethan Galstad <nagios@nagios.org> | ||
6 | * | ||
7 | * The Nagios Plugins are free software; you can redistribute them | ||
8 | * and/or modify them under the terms of the GNU General Public | ||
9 | * License as published by the Free Software Foundation; either | ||
10 | * version 2 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | * | ||
21 | * $Id$ | ||
22 | * | ||
23 | *****************************************************************************/ | ||
24 | |||
25 | #define PROGRAM check_tcp | ||
26 | #define DESCRIPTION "Check a TCP port" | ||
27 | #define AUTHOR "Ethan Galstad" | ||
28 | #define EMAIL "nagios@nagios.org" | ||
29 | #define COPYRIGHTDATE "1999" | ||
30 | |||
31 | #include "config.h" | ||
32 | #include "common.h" | ||
33 | #include "netutils.h" | ||
34 | #include "utils.h" | ||
35 | |||
36 | #ifdef HAVE_SSL_H | ||
37 | #include <rsa.h> | ||
38 | #include <crypto.h> | ||
39 | #include <x509.h> | ||
40 | #include <pem.h> | ||
41 | #include <ssl.h> | ||
42 | #include <err.h> | ||
43 | #endif | ||
44 | |||
45 | #ifdef HAVE_OPENSSL_SSL_H | ||
46 | #include <openssl/rsa.h> | ||
47 | #include <openssl/crypto.h> | ||
48 | #include <openssl/x509.h> | ||
49 | #include <openssl/pem.h> | ||
50 | #include <openssl/ssl.h> | ||
51 | #include <openssl/err.h> | ||
52 | #endif | ||
53 | |||
54 | #ifdef HAVE_SSL | ||
55 | SSL_CTX *ctx; | ||
56 | SSL *ssl; | ||
57 | int connect_SSL (void); | ||
58 | #endif | ||
59 | |||
60 | #define TCP_PROTOCOL 1 | ||
61 | #define UDP_PROTOCOL 2 | ||
62 | |||
63 | int process_arguments (int, char **); | ||
64 | void print_usage (void); | ||
65 | void print_help (void); | ||
66 | |||
67 | char *PROGNAME = NULL; | ||
68 | char *SERVICE = NULL; | ||
69 | char *SEND = NULL; | ||
70 | char *EXPECT = NULL; | ||
71 | char *QUIT = NULL; | ||
72 | int PROTOCOL = 0; | ||
73 | int PORT = 0; | ||
74 | |||
75 | int server_port = 0; | ||
76 | char *server_address = NULL; | ||
77 | char *server_send = NULL; | ||
78 | char *server_quit = NULL; | ||
79 | char **server_expect = NULL; | ||
80 | int server_expect_count = 0; | ||
81 | char **warn_codes = NULL; | ||
82 | int warn_codes_count = 0; | ||
83 | char **crit_codes = NULL; | ||
84 | int crit_codes_count = 0; | ||
85 | int delay = 0; | ||
86 | int warning_time = 0; | ||
87 | int check_warning_time = FALSE; | ||
88 | int critical_time = 0; | ||
89 | int check_critical_time = FALSE; | ||
90 | int verbose = FALSE; | ||
91 | int use_ssl = FALSE; | ||
92 | int sd; | ||
93 | |||
94 | int | ||
95 | main (int argc, char **argv) | ||
96 | { | ||
97 | int result; | ||
98 | int i; | ||
99 | char buffer[MAX_INPUT_BUFFER] = ""; | ||
100 | char *status = NULL; | ||
101 | char *output = NULL; | ||
102 | char *ptr = NULL; | ||
103 | |||
104 | if (strstr (argv[0], "check_udp")) { | ||
105 | PROGNAME = strscpy (PROGNAME, "check_udp"); | ||
106 | SERVICE = strscpy (SERVICE, "UDP"); | ||
107 | SEND = NULL; | ||
108 | EXPECT = NULL; | ||
109 | QUIT = NULL; | ||
110 | PROTOCOL = UDP_PROTOCOL; | ||
111 | PORT = 0; | ||
112 | } | ||
113 | else if (strstr (argv[0], "check_tcp")) { | ||
114 | PROGNAME = strscpy (PROGNAME, "check_tcp"); | ||
115 | SERVICE = strscpy (SERVICE, "TCP"); | ||
116 | SEND = NULL; | ||
117 | EXPECT = NULL; | ||
118 | QUIT = NULL; | ||
119 | PROTOCOL = TCP_PROTOCOL; | ||
120 | PORT = 0; | ||
121 | } | ||
122 | else if (strstr (argv[0], "check_ftp")) { | ||
123 | PROGNAME = strscpy (PROGNAME, "check_ftp"); | ||
124 | SERVICE = strscpy (SERVICE, "FTP"); | ||
125 | SEND = NULL; | ||
126 | EXPECT = strscpy (EXPECT, "220"); | ||
127 | QUIT = strscpy (QUIT, "QUIT\r\n"); | ||
128 | PROTOCOL = TCP_PROTOCOL; | ||
129 | PORT = 21; | ||
130 | } | ||
131 | else if (strstr (argv[0], "check_smtp")) { | ||
132 | PROGNAME = strscpy (PROGNAME, "check_smtp"); | ||
133 | SERVICE = strscpy (SERVICE, "SMTP"); | ||
134 | SEND = NULL; | ||
135 | EXPECT = strscpy (EXPECT, "220"); | ||
136 | QUIT = strscpy (QUIT, "QUIT\r\n"); | ||
137 | PROTOCOL = TCP_PROTOCOL; | ||
138 | PORT = 25; | ||
139 | } | ||
140 | else if (strstr (argv[0], "check_pop")) { | ||
141 | PROGNAME = strscpy (PROGNAME, "check_pop"); | ||
142 | SERVICE = strscpy (SERVICE, "POP"); | ||
143 | SEND = NULL; | ||
144 | EXPECT = strscpy (EXPECT, "110"); | ||
145 | QUIT = strscpy (QUIT, "QUIT\r\n"); | ||
146 | PROTOCOL = TCP_PROTOCOL; | ||
147 | PORT = 110; | ||
148 | } | ||
149 | else if (strstr (argv[0], "check_imap")) { | ||
150 | PROGNAME = strscpy (PROGNAME, "check_imap"); | ||
151 | SERVICE = strscpy (SERVICE, "IMAP"); | ||
152 | SEND = NULL; | ||
153 | EXPECT = strscpy (EXPECT, "* OK"); | ||
154 | QUIT = strscpy (QUIT, "a1 LOGOUT\r\n"); | ||
155 | PROTOCOL = TCP_PROTOCOL; | ||
156 | PORT = 143; | ||
157 | } | ||
158 | #ifdef HAVE_SSL | ||
159 | else if (strstr(argv[0],"check_simap")) { | ||
160 | PROGNAME=strscpy(PROGNAME,"check_simap"); | ||
161 | SERVICE=strscpy(SERVICE,"SIMAP"); | ||
162 | SEND=NULL; | ||
163 | EXPECT=strscpy(EXPECT,"* OK"); | ||
164 | QUIT=strscpy(QUIT,"a1 LOGOUT\n"); | ||
165 | PROTOCOL=TCP_PROTOCOL; | ||
166 | use_ssl=TRUE; | ||
167 | PORT=993; | ||
168 | } | ||
169 | #endif | ||
170 | else if (strstr (argv[0], "check_nntp")) { | ||
171 | PROGNAME = strscpy (PROGNAME, "check_nntp"); | ||
172 | SERVICE = strscpy (SERVICE, "NNTP"); | ||
173 | SEND = NULL; | ||
174 | EXPECT = NULL; | ||
175 | server_expect = realloc (server_expect, ++server_expect_count); | ||
176 | server_expect[server_expect_count - 1] = strscpy (EXPECT, "200"); | ||
177 | server_expect = realloc (server_expect, ++server_expect_count); | ||
178 | server_expect[server_expect_count - 1] = strscpy (NULL, "201"); | ||
179 | QUIT = strscpy (QUIT, "QUIT\r\n"); | ||
180 | PROTOCOL = TCP_PROTOCOL; | ||
181 | PORT = 119; | ||
182 | } | ||
183 | else { | ||
184 | usage ("ERROR: Generic check_tcp called with unknown service\n"); | ||
185 | } | ||
186 | |||
187 | server_address = strscpy (NULL, "127.0.0.1"); | ||
188 | server_port = PORT; | ||
189 | server_send = SEND; | ||
190 | server_quit = QUIT; | ||
191 | |||
192 | if (process_arguments (argc, argv) == ERROR) | ||
193 | usage ("Could not parse arguments\n"); | ||
194 | |||
195 | /* use default expect if none listed in process_arguments() */ | ||
196 | if (EXPECT && server_expect_count == 0) { | ||
197 | server_expect = malloc (1); | ||
198 | server_expect[server_expect_count - 1] = EXPECT; | ||
199 | } | ||
200 | |||
201 | /* initialize alarm signal handling */ | ||
202 | signal (SIGALRM, socket_timeout_alarm_handler); | ||
203 | |||
204 | /* set socket timeout */ | ||
205 | alarm (socket_timeout); | ||
206 | |||
207 | /* try to connect to the host at the given port number */ | ||
208 | time (&start_time); | ||
209 | #ifdef HAVE_SSL | ||
210 | if (use_ssl) | ||
211 | result = connect_SSL (); | ||
212 | else | ||
213 | #endif | ||
214 | { | ||
215 | if (PROTOCOL == UDP_PROTOCOL) | ||
216 | result = my_udp_connect (server_address, server_port, &sd); | ||
217 | else /* default is TCP */ | ||
218 | result = my_tcp_connect (server_address, server_port, &sd); | ||
219 | } | ||
220 | |||
221 | if (result == STATE_CRITICAL) | ||
222 | return STATE_CRITICAL; | ||
223 | |||
224 | if (server_send != NULL) { /* Something to send? */ | ||
225 | snprintf (buffer, MAX_INPUT_BUFFER - 1, "%s\r\n", server_send); | ||
226 | buffer[MAX_INPUT_BUFFER - 1] = 0; | ||
227 | #ifdef HAVE_SSL | ||
228 | if (use_ssl) | ||
229 | SSL_write(ssl,buffer,strlen(buffer)); | ||
230 | else | ||
231 | #endif | ||
232 | send (sd, buffer, strlen (buffer), 0); | ||
233 | } | ||
234 | |||
235 | if (delay > 0) { | ||
236 | start_time = start_time + delay; | ||
237 | sleep (delay); | ||
238 | } | ||
239 | |||
240 | if (server_send || server_expect_count > 0) { | ||
241 | |||
242 | /* watch for the expect string */ | ||
243 | #ifdef HAVE_SSL | ||
244 | if (use_ssl && SSL_read (ssl, buffer, MAX_INPUT_BUFFER - 1)>=0) | ||
245 | status = strscat(status,buffer); | ||
246 | else | ||
247 | #endif | ||
248 | { | ||
249 | if (recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0) >= 0) | ||
250 | status = strscat (status, buffer); | ||
251 | } | ||
252 | strip (status); | ||
253 | |||
254 | /* return a CRITICAL status if we couldn't read any data */ | ||
255 | if (status == NULL) | ||
256 | terminate (STATE_CRITICAL, "No data received from host\n"); | ||
257 | |||
258 | if (status && verbose) | ||
259 | printf ("%s\n", status); | ||
260 | |||
261 | if (server_expect_count > 0) { | ||
262 | for (i = 0;; i++) { | ||
263 | printf ("%d %d\n", i, server_expect_count); | ||
264 | if (i >= server_expect_count) | ||
265 | terminate (STATE_WARNING, "Invalid response from host\n"); | ||
266 | if (strstr (status, server_expect[i])) | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | if (server_quit) | ||
273 | #ifdef HAVE_SSL | ||
274 | if (use_ssl) { | ||
275 | SSL_write (ssl, QUIT, strlen (QUIT)); | ||
276 | SSL_shutdown (ssl); | ||
277 | SSL_free (ssl); | ||
278 | SSL_CTX_free (ctx); | ||
279 | } | ||
280 | else | ||
281 | #endif | ||
282 | send (sd, server_quit, strlen (server_quit), 0); | ||
283 | |||
284 | /* close the connection */ | ||
285 | close (sd); | ||
286 | |||
287 | time (&end_time); | ||
288 | |||
289 | if (check_critical_time == TRUE && (end_time - start_time) > critical_time) | ||
290 | result = STATE_CRITICAL; | ||
291 | else if (check_warning_time == TRUE | ||
292 | && (end_time - start_time) > warning_time) result = STATE_WARNING; | ||
293 | |||
294 | /* reset the alarm */ | ||
295 | alarm (0); | ||
296 | |||
297 | printf | ||
298 | ("%s %s - %d second response time on port %d", | ||
299 | SERVICE, | ||
300 | state_text (result), (int) (end_time - start_time), server_port); | ||
301 | |||
302 | if (status) | ||
303 | printf (" [%s]\n", status); | ||
304 | else | ||
305 | printf ("\n"); | ||
306 | |||
307 | return result; | ||
308 | } | ||
309 | |||
310 | |||
311 | |||
312 | |||
313 | |||
314 | |||
315 | |||
316 | /* process command-line arguments */ | ||
317 | int | ||
318 | process_arguments (int argc, char **argv) | ||
319 | { | ||
320 | int c; | ||
321 | |||
322 | #ifdef HAVE_GETOPT_H | ||
323 | int option_index = 0; | ||
324 | static struct option long_options[] = { | ||
325 | {"hostname", required_argument, 0, 'H'}, | ||
326 | {"critical-time", required_argument, 0, 'c'}, | ||
327 | {"warning-time", required_argument, 0, 'w'}, | ||
328 | {"critical-codes", required_argument, 0, 'C'}, | ||
329 | {"warning-codes", required_argument, 0, 'W'}, | ||
330 | {"timeout", required_argument, 0, 't'}, | ||
331 | {"protocol", required_argument, 0, 'P'}, | ||
332 | {"port", required_argument, 0, 'p'}, | ||
333 | {"send", required_argument, 0, 's'}, | ||
334 | {"expect", required_argument, 0, 'e'}, | ||
335 | {"quit", required_argument, 0, 'q'}, | ||
336 | {"delay", required_argument, 0, 'd'}, | ||
337 | {"verbose", no_argument, 0, 'v'}, | ||
338 | {"version", no_argument, 0, 'V'}, | ||
339 | {"help", no_argument, 0, 'h'}, | ||
340 | {0, 0, 0, 0} | ||
341 | }; | ||
342 | #endif | ||
343 | |||
344 | if (argc < 2) | ||
345 | usage ("No arguments found\n"); | ||
346 | |||
347 | /* backwards compatibility */ | ||
348 | for (c = 1; c < argc; c++) { | ||
349 | if (strcmp ("-to", argv[c]) == 0) | ||
350 | strcpy (argv[c], "-t"); | ||
351 | else if (strcmp ("-wt", argv[c]) == 0) | ||
352 | strcpy (argv[c], "-w"); | ||
353 | else if (strcmp ("-ct", argv[c]) == 0) | ||
354 | strcpy (argv[c], "-c"); | ||
355 | } | ||
356 | |||
357 | if (!is_option (argv[1])) { | ||
358 | server_address = argv[1]; | ||
359 | argv[1] = argv[0]; | ||
360 | argv = &argv[1]; | ||
361 | argc--; | ||
362 | } | ||
363 | |||
364 | while (1) { | ||
365 | #ifdef HAVE_GETOPT_H | ||
366 | c = | ||
367 | getopt_long (argc, argv, "+hVvH:s:e:q:c:w:t:p:C:W:d:S", long_options, | ||
368 | &option_index); | ||
369 | #else | ||
370 | c = getopt (argc, argv, "+hVvH:s:e:q:c:w:t:p:C:W:d:S"); | ||
371 | #endif | ||
372 | |||
373 | if (c == -1 || c == EOF || c == 1) | ||
374 | break; | ||
375 | |||
376 | switch (c) { | ||
377 | case '?': /* print short usage statement if args not parsable */ | ||
378 | printf ("%s: Unknown argument: %s\n\n", my_basename (argv[0]), optarg); | ||
379 | print_usage (); | ||
380 | exit (STATE_UNKNOWN); | ||
381 | case 'h': /* help */ | ||
382 | print_help (); | ||
383 | exit (STATE_OK); | ||
384 | case 'V': /* version */ | ||
385 | print_revision (PROGNAME, "$Revision$"); | ||
386 | exit (STATE_OK); | ||
387 | case 'v': /* verbose mode */ | ||
388 | verbose = TRUE; | ||
389 | break; | ||
390 | case 'H': /* hostname */ | ||
391 | if (is_host (optarg) == FALSE) | ||
392 | usage ("Invalid host name/address\n"); | ||
393 | server_address = optarg; | ||
394 | break; | ||
395 | case 'c': /* critical */ | ||
396 | if (!is_intnonneg (optarg)) | ||
397 | usage ("Critical threshold must be a nonnegative integer\n"); | ||
398 | critical_time = atoi (optarg); | ||
399 | check_critical_time = TRUE; | ||
400 | break; | ||
401 | case 'w': /* warning */ | ||
402 | if (!is_intnonneg (optarg)) | ||
403 | usage ("Warning threshold must be a nonnegative integer\n"); | ||
404 | warning_time = atoi (optarg); | ||
405 | check_warning_time = TRUE; | ||
406 | break; | ||
407 | case 'C': | ||
408 | crit_codes = realloc (crit_codes, ++crit_codes_count); | ||
409 | crit_codes[crit_codes_count - 1] = optarg; | ||
410 | break; | ||
411 | case 'W': | ||
412 | warn_codes = realloc (warn_codes, ++warn_codes_count); | ||
413 | warn_codes[warn_codes_count - 1] = optarg; | ||
414 | break; | ||
415 | case 't': /* timeout */ | ||
416 | if (!is_intpos (optarg)) | ||
417 | usage ("Timeout interval must be a positive integer\n"); | ||
418 | socket_timeout = atoi (optarg); | ||
419 | break; | ||
420 | case 'p': /* port */ | ||
421 | if (!is_intpos (optarg)) | ||
422 | usage ("Server port must be a positive integer\n"); | ||
423 | server_port = atoi (optarg); | ||
424 | break; | ||
425 | case 's': | ||
426 | server_send = optarg; | ||
427 | break; | ||
428 | case 'e': | ||
429 | EXPECT = NULL; | ||
430 | if (server_expect_count == 0) | ||
431 | server_expect = malloc (++server_expect_count); | ||
432 | else | ||
433 | server_expect = realloc (server_expect, ++server_expect_count); | ||
434 | server_expect[server_expect_count - 1] = optarg; | ||
435 | break; | ||
436 | case 'q': | ||
437 | server_quit = optarg; | ||
438 | break; | ||
439 | case 'd': | ||
440 | if (is_intpos (optarg)) | ||
441 | delay = atoi (optarg); | ||
442 | else | ||
443 | usage ("Delay must be a positive integer\n"); | ||
444 | break; | ||
445 | case 'S': | ||
446 | #ifndef HAVE_SSL | ||
447 | terminate (STATE_UNKNOWN, | ||
448 | "SSL support not available. Install OpenSSL and recompile."); | ||
449 | #endif | ||
450 | use_ssl = TRUE; | ||
451 | break; | ||
452 | } | ||
453 | } | ||
454 | |||
455 | if (server_address == NULL) | ||
456 | usage ("You must provide a server address\n"); | ||
457 | |||
458 | return OK; | ||
459 | } | ||
460 | |||
461 | |||
462 | |||
463 | |||
464 | |||
465 | void | ||
466 | print_usage (void) | ||
467 | { | ||
468 | printf | ||
469 | ("Usage: %s -H host -p port [-w warn_time] [-c crit_time] [-s send]\n" | ||
470 | " [-e expect] [-W wait] [-t to_sec] [-v]\n", PROGNAME); | ||
471 | } | ||
472 | |||
473 | |||
474 | |||
475 | |||
476 | |||
477 | void | ||
478 | print_help (void) | ||
479 | { | ||
480 | print_revision (PROGNAME, "$Revision$"); | ||
481 | printf | ||
482 | ("Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)\n\n" | ||
483 | "This plugin tests %s connections with the specified host.\n\n", | ||
484 | SERVICE); | ||
485 | print_usage (); | ||
486 | printf | ||
487 | ("Options:\n" | ||
488 | " -H, --hostname=ADDRESS\n" | ||
489 | " Host name argument for servers using host headers (use numeric\n" | ||
490 | " address if possible to bypass DNS lookup).\n" | ||
491 | " -p, --port=INTEGER\n" | ||
492 | " Port number\n" | ||
493 | " -s, --send=STRING\n" | ||
494 | " String to send to the server\n" | ||
495 | " -e, --expect=STRING\n" | ||
496 | " String to expect in server response" | ||
497 | " -W, --wait=INTEGER\n" | ||
498 | " Seconds to wait between sending string and polling for response\n" | ||
499 | " -w, --warning=INTEGER\n" | ||
500 | " Response time to result in warning status (seconds)\n" | ||
501 | " -c, --critical=INTEGER\n" | ||
502 | " Response time to result in critical status (seconds)\n" | ||
503 | " -t, --timeout=INTEGER\n" | ||
504 | " Seconds before connection times out (default: %d)\n" | ||
505 | " -v" | ||
506 | " Show details for command-line debugging (do not use with nagios server)\n" | ||
507 | " -h, --help\n" | ||
508 | " Print detailed help screen\n" | ||
509 | " -V, --version\n" | ||
510 | " Print version information\n", DEFAULT_SOCKET_TIMEOUT); | ||
511 | } | ||
512 | |||
513 | |||
514 | #ifdef HAVE_SSL | ||
515 | int | ||
516 | connect_SSL (void) | ||
517 | { | ||
518 | SSL_METHOD *meth; | ||
519 | |||
520 | /* Initialize SSL context */ | ||
521 | SSLeay_add_ssl_algorithms (); | ||
522 | meth = SSLv2_client_method (); | ||
523 | SSL_load_error_strings (); | ||
524 | if ((ctx = SSL_CTX_new (meth)) == NULL) | ||
525 | { | ||
526 | printf ("ERROR: Cannot create SSL context.\n"); | ||
527 | return STATE_CRITICAL; | ||
528 | } | ||
529 | |||
530 | /* Initialize alarm signal handling */ | ||
531 | signal (SIGALRM, socket_timeout_alarm_handler); | ||
532 | |||
533 | /* Set socket timeout */ | ||
534 | alarm (socket_timeout); | ||
535 | |||
536 | /* Save start time */ | ||
537 | time (&start_time); | ||
538 | |||
539 | /* Make TCP connection */ | ||
540 | if (my_tcp_connect (server_address, server_port, &sd) == STATE_OK) | ||
541 | { | ||
542 | /* Do the SSL handshake */ | ||
543 | if ((ssl = SSL_new (ctx)) != NULL) | ||
544 | { | ||
545 | SSL_set_fd (ssl, sd); | ||
546 | if (SSL_connect (ssl) != -1) | ||
547 | return OK; | ||
548 | ERR_print_errors_fp (stderr); | ||
549 | } | ||
550 | else | ||
551 | { | ||
552 | printf ("ERROR: Cannot initiate SSL handshake.\n"); | ||
553 | } | ||
554 | SSL_free (ssl); | ||
555 | } | ||
556 | |||
557 | SSL_CTX_free (ctx); | ||
558 | close (sd); | ||
559 | |||
560 | return STATE_CRITICAL; | ||
561 | } | ||
562 | #endif | ||
563 | |||