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 /* progname "check_tcp" changes depending on symlink called */
20 char *progname;
21 const char *revision = "$Revision$";
22 const char *copyright = "1999-2003";
23 const char *email = "nagiosplug-devel@lists.sourceforge.net";
25 #include "common.h"
26 #include "netutils.h"
27 #include "utils.h"
29 #ifdef HAVE_SSL_H
30 # include <rsa.h>
31 # include <crypto.h>
32 # include <x509.h>
33 # include <pem.h>
34 # include <ssl.h>
35 # include <err.h>
36 #else
37 # ifdef HAVE_OPENSSL_SSL_H
38 # include <openssl/rsa.h>
39 # include <openssl/crypto.h>
40 # include <openssl/x509.h>
41 # include <openssl/pem.h>
42 # include <openssl/ssl.h>
43 # include <openssl/err.h>
44 # endif
45 #endif
47 #ifdef HAVE_SSL
48 SSL_CTX *ctx;
49 SSL *ssl;
50 int connect_SSL (void);
51 #endif
53 enum {
54 TCP_PROTOCOL = 1,
55 UDP_PROTOCOL = 2,
56 MAXBUF = 1024
57 };
59 int process_arguments (int, char **);
60 int my_recv (void);
61 void print_help (void);
62 void print_usage (void);
64 char *SERVICE = NULL;
65 char *SEND = NULL;
66 char *EXPECT = NULL;
67 char *QUIT = NULL;
68 int PROTOCOL = 0;
69 int PORT = 0;
71 int server_port = 0;
72 char *server_address = NULL;
73 char *server_send = NULL;
74 char *server_quit = NULL;
75 char **server_expect = NULL;
76 size_t server_expect_count = 0;
77 int maxbytes = 0;
78 char **warn_codes = NULL;
79 size_t warn_codes_count = 0;
80 char **crit_codes = NULL;
81 size_t crit_codes_count = 0;
82 unsigned int delay = 0;
83 double warning_time = 0;
84 int check_warning_time = FALSE;
85 double critical_time = 0;
86 int check_critical_time = FALSE;
87 int hide_output = FALSE;
88 double elapsed_time = 0;
89 long microsec;
90 int verbose = FALSE;
91 int use_ssl = FALSE;
92 int sd = 0;
93 char *buffer;
99 \f
100 int
101 main (int argc, char **argv)
102 {
103 int result;
104 int i;
105 char *status;
106 struct timeval tv;
108 setlocale (LC_ALL, "");
109 bindtextdomain (PACKAGE, LOCALEDIR);
110 textdomain (PACKAGE);
112 if (strstr (argv[0], "check_udp")) {
113 progname = strdup ("check_udp");
114 SERVICE = strdup ("UDP");
115 SEND = NULL;
116 EXPECT = NULL;
117 QUIT = NULL;
118 PROTOCOL = UDP_PROTOCOL;
119 PORT = 0;
120 }
121 else if (strstr (argv[0], "check_tcp")) {
122 progname = strdup ("check_tcp");
123 SERVICE = strdup ("TCP");
124 SEND = NULL;
125 EXPECT = NULL;
126 QUIT = NULL;
127 PROTOCOL = TCP_PROTOCOL;
128 PORT = 0;
129 }
130 else if (strstr (argv[0], "check_ftp")) {
131 progname = strdup ("check_ftp");
132 SERVICE = strdup ("FTP");
133 SEND = NULL;
134 EXPECT = strdup ("220");
135 QUIT = strdup ("QUIT\r\n");
136 PROTOCOL = TCP_PROTOCOL;
137 PORT = 21;
138 }
139 else if (strstr (argv[0], "check_smtp")) {
140 progname = strdup ("check_smtp");
141 SERVICE = strdup ("SMTP");
142 SEND = NULL;
143 EXPECT = strdup ("220");
144 QUIT = strdup ("QUIT\r\n");
145 PROTOCOL = TCP_PROTOCOL;
146 PORT = 25;
147 }
148 else if (strstr (argv[0], "check_pop")) {
149 progname = strdup ("check_pop");
150 SERVICE = strdup ("POP");
151 SEND = NULL;
152 EXPECT = strdup ("+OK");
153 QUIT = strdup ("QUIT\r\n");
154 PROTOCOL = TCP_PROTOCOL;
155 PORT = 110;
156 }
157 else if (strstr (argv[0], "check_imap")) {
158 progname = strdup ("check_imap");
159 SERVICE = strdup ("IMAP");
160 SEND = NULL;
161 EXPECT = strdup ("* OK");
162 QUIT = strdup ("a1 LOGOUT\r\n");
163 PROTOCOL = TCP_PROTOCOL;
164 PORT = 143;
165 }
166 #ifdef HAVE_SSL
167 else if (strstr(argv[0],"check_simap")) {
168 progname = strdup ("check_simap");
169 SERVICE = strdup ("SIMAP");
170 SEND=NULL;
171 EXPECT = strdup ("* OK");
172 QUIT = strdup ("a1 LOGOUT\r\n");
173 PROTOCOL=TCP_PROTOCOL;
174 use_ssl=TRUE;
175 PORT=993;
176 }
177 else if (strstr(argv[0],"check_spop")) {
178 progname = strdup ("check_spop");
179 SERVICE = strdup ("SPOP");
180 SEND=NULL;
181 EXPECT = strdup ("+OK");
182 QUIT = strdup ("QUIT\r\n");
183 PROTOCOL=TCP_PROTOCOL;
184 use_ssl=TRUE;
185 PORT=995;
186 }
187 #endif
188 else if (strstr (argv[0], "check_nntp")) {
189 progname = strdup ("check_nntp");
190 SERVICE = strdup ("NNTP");
191 SEND = NULL;
192 EXPECT = NULL;
193 server_expect = realloc (server_expect, sizeof (char *) * (++server_expect_count));
194 asprintf (&server_expect[server_expect_count - 1], "200");
195 server_expect = realloc (server_expect, sizeof (char *) * (++server_expect_count));
196 asprintf (&server_expect[server_expect_count - 1], "201");
197 asprintf (&QUIT, "QUIT\r\n");
198 PROTOCOL = TCP_PROTOCOL;
199 PORT = 119;
200 }
201 else {
202 progname = strdup ("check_tcp");
203 usage (_("ERROR: Generic check_tcp called with unknown service\n"));
204 }
206 server_address = strdup ("127.0.0.1");
207 server_port = PORT;
208 server_send = SEND;
209 server_quit = QUIT;
210 status = strdup ("");
212 if (process_arguments (argc, argv) == ERROR)
213 usage (_("Could not parse arguments\n"));
215 /* use default expect if none listed in process_arguments() */
216 if (EXPECT && server_expect_count == 0) {
217 server_expect = malloc (sizeof (char *) * (++server_expect_count));
218 server_expect[server_expect_count - 1] = EXPECT;
219 }
221 /* initialize alarm signal handling */
222 signal (SIGALRM, socket_timeout_alarm_handler);
224 /* set socket timeout */
225 alarm (socket_timeout);
227 /* try to connect to the host at the given port number */
228 gettimeofday (&tv, NULL);
229 #ifdef HAVE_SSL
230 if (use_ssl)
231 result = connect_SSL ();
232 else
233 #endif
234 {
235 if (PROTOCOL == UDP_PROTOCOL)
236 result = my_udp_connect (server_address, server_port, &sd);
237 else
238 /* default is TCP */
239 result = my_tcp_connect (server_address, server_port, &sd);
240 }
242 if (result == STATE_CRITICAL)
243 return STATE_CRITICAL;
245 if (server_send != NULL) { /* Something to send? */
246 asprintf (&server_send, "%s\r\n", server_send);
247 #ifdef HAVE_SSL
248 if (use_ssl)
249 SSL_write(ssl, server_send, (int)strlen(server_send));
250 else
251 #endif
252 send (sd, server_send, strlen(server_send), 0);
253 }
255 if (delay > 0) {
256 tv.tv_sec += delay;
257 sleep (delay);
258 }
260 if (server_send || server_expect_count > 0) {
262 buffer = malloc (MAXBUF);
263 memset (buffer, '\0', MAXBUF);
264 /* watch for the expect string */
265 while ((i = my_recv ()) > 0) {
266 buffer[i] = '\0';
267 asprintf (&status, "%s%s", status, buffer);
268 if (buffer[i-2] == '\r' && buffer[i-1] == '\n')
269 break;
270 if (maxbytes>0 && strlen(status) >= (unsigned)maxbytes)
271 break;
272 }
274 /* return a CRITICAL status if we couldn't read any data */
275 if (strlen(status) == 0)
276 die (STATE_CRITICAL, _("No data received from host\n"));
278 strip (status);
280 if (status && verbose)
281 printf ("%s\n", status);
283 if (server_expect_count > 0) {
284 for (i = 0;; i++) {
285 if (verbose)
286 printf ("%d %d\n", i, (int)server_expect_count);
287 if (i >= (int)server_expect_count)
288 die (STATE_WARNING, _("Invalid response from host\n"));
289 if (strstr (status, server_expect[i]))
290 break;
291 }
292 }
293 }
295 if (server_quit != NULL) {
296 #ifdef HAVE_SSL
297 if (use_ssl) {
298 SSL_write (ssl, server_quit, (int)strlen(server_quit));
299 SSL_shutdown (ssl);
300 SSL_free (ssl);
301 SSL_CTX_free (ctx);
302 }
303 else {
304 #endif
305 send (sd, server_quit, strlen (server_quit), 0);
306 #ifdef HAVE_SSL
307 }
308 #endif
309 }
311 /* close the connection */
312 if (sd)
313 close (sd);
315 microsec = deltime (tv);
316 elapsed_time = (double)microsec / 1.0e6;
318 if (check_critical_time == TRUE && elapsed_time > critical_time)
319 result = STATE_CRITICAL;
320 else if (check_warning_time == TRUE && elapsed_time > warning_time)
321 result = STATE_WARNING;
323 /* reset the alarm */
324 alarm (0);
326 printf
327 (_("%s %s%s - %.3f second response time on port %d"),
328 SERVICE,
329 state_text (result),
330 (was_refused) ? " (refused)" : "",
331 elapsed_time, server_port);
333 if (hide_output == FALSE && status && strlen(status) > 0)
334 printf (" [%s]", status);
336 printf (" |%s\n", fperfdata ("time", elapsed_time, "s",
337 TRUE, warning_time,
338 TRUE, critical_time,
339 TRUE, 0,
340 TRUE, socket_timeout));
342 return result;
343 }
344 \f
348 /* process command-line arguments */
349 int
350 process_arguments (int argc, char **argv)
351 {
352 int c;
354 int option = 0;
355 static struct option longopts[] = {
356 {"hostname", required_argument, 0, 'H'},
357 {"critical-time", required_argument, 0, 'c'},
358 {"warning-time", required_argument, 0, 'w'},
359 {"critical-codes", required_argument, 0, 'C'},
360 {"warning-codes", required_argument, 0, 'W'},
361 {"timeout", required_argument, 0, 't'},
362 {"protocol", required_argument, 0, 'P'},
363 {"port", required_argument, 0, 'p'},
364 {"send", required_argument, 0, 's'},
365 {"expect", required_argument, 0, 'e'},
366 {"maxbytes", required_argument, 0, 'm'},
367 {"quit", required_argument, 0, 'q'},
368 {"jail", required_argument, 0, 'j'},
369 {"delay", required_argument, 0, 'd'},
370 {"refuse", required_argument, 0, 'r'},
371 {"use-ipv4", no_argument, 0, '4'},
372 {"use-ipv6", no_argument, 0, '6'},
373 {"verbose", no_argument, 0, 'v'},
374 {"version", no_argument, 0, 'V'},
375 {"help", no_argument, 0, 'h'},
376 {0, 0, 0, 0}
377 };
379 if (argc < 2)
380 usage ("No arguments found\n");
382 /* backwards compatibility */
383 for (c = 1; c < argc; c++) {
384 if (strcmp ("-to", argv[c]) == 0)
385 strcpy (argv[c], "-t");
386 else if (strcmp ("-wt", argv[c]) == 0)
387 strcpy (argv[c], "-w");
388 else if (strcmp ("-ct", argv[c]) == 0)
389 strcpy (argv[c], "-c");
390 }
392 if (!is_option (argv[1])) {
393 server_address = argv[1];
394 argv[1] = argv[0];
395 argv = &argv[1];
396 argc--;
397 }
399 while (1) {
400 c = getopt_long (argc, argv, "+hVv46H:s:e:q:m:c:w:t:p:C:W:d:Sr:j",
401 longopts, &option);
403 if (c == -1 || c == EOF || c == 1)
404 break;
406 switch (c) {
407 case '?': /* print short usage statement if args not parsable */
408 printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
409 print_usage ();
410 exit (STATE_UNKNOWN);
411 case 'h': /* help */
412 print_help ();
413 exit (STATE_OK);
414 case 'V': /* version */
415 print_revision (progname, "$Revision$");
416 exit (STATE_OK);
417 case 'v': /* verbose mode */
418 verbose = TRUE;
419 break;
420 case '4':
421 address_family = AF_INET;
422 break;
423 case '6':
424 #ifdef USE_IPV6
425 address_family = AF_INET6;
426 #else
427 usage (_("IPv6 support not available\n"));
428 #endif
429 break;
430 case 'H': /* hostname */
431 if (is_host (optarg) == FALSE)
432 usage2 (_("invalid host name or address"), optarg);
433 server_address = optarg;
434 break;
435 case 'c': /* critical */
436 if (!is_intnonneg (optarg))
437 usage (_("Critical threshold must be a nonnegative integer\n"));
438 else
439 critical_time = strtod (optarg, NULL);
440 check_critical_time = TRUE;
441 break;
442 case 'j': /* hide output */
443 hide_output = TRUE;
444 break;
445 case 'w': /* warning */
446 if (!is_intnonneg (optarg))
447 usage (_("Warning threshold must be a nonnegative integer\n"));
448 else
449 warning_time = strtod (optarg, NULL);
450 check_warning_time = TRUE;
451 break;
452 case 'C':
453 crit_codes = realloc (crit_codes, ++crit_codes_count);
454 crit_codes[crit_codes_count - 1] = optarg;
455 break;
456 case 'W':
457 warn_codes = realloc (warn_codes, ++warn_codes_count);
458 warn_codes[warn_codes_count - 1] = optarg;
459 break;
460 case 't': /* timeout */
461 if (!is_intpos (optarg))
462 usage (_("Timeout interval must be a positive integer\n"));
463 else
464 socket_timeout = atoi (optarg);
465 break;
466 case 'p': /* port */
467 if (!is_intpos (optarg))
468 usage (_("Server port must be a positive integer\n"));
469 else
470 server_port = atoi (optarg);
471 break;
472 case 's':
473 server_send = optarg;
474 break;
475 case 'e': /* expect string (may be repeated) */
476 EXPECT = NULL;
477 if (server_expect_count == 0)
478 server_expect = malloc (sizeof (char *) * (++server_expect_count));
479 else
480 server_expect = realloc (server_expect, sizeof (char *) * (++server_expect_count));
481 server_expect[server_expect_count - 1] = optarg;
482 break;
483 case 'm':
484 if (!is_intpos (optarg))
485 usage (_("Maxbytes must be a positive integer\n"));
486 else
487 maxbytes = atoi (optarg);
488 case 'q':
489 asprintf(&server_quit, "%s\r\n", optarg);
490 break;
491 case 'r':
492 if (!strncmp(optarg,"ok",2))
493 econn_refuse_state = STATE_OK;
494 else if (!strncmp(optarg,"warn",4))
495 econn_refuse_state = STATE_WARNING;
496 else if (!strncmp(optarg,"crit",4))
497 econn_refuse_state = STATE_CRITICAL;
498 else
499 usage (_("Refuse mut be one of ok, warn, crit\n"));
500 break;
501 case 'd':
502 if (is_intpos (optarg))
503 delay = atoi (optarg);
504 else
505 usage (_("Delay must be a positive integer\n"));
506 break;
507 case 'S':
508 #ifndef HAVE_SSL
509 die (STATE_UNKNOWN,
510 _("SSL support not available. Install OpenSSL and recompile."));
511 #endif
512 use_ssl = TRUE;
513 break;
514 }
515 }
517 if (server_address == NULL)
518 usage (_("You must provide a server address\n"));
520 return OK;
521 }
522 \f
524 #ifdef HAVE_SSL
525 int
526 connect_SSL (void)
527 {
528 SSL_METHOD *meth;
530 /* Initialize SSL context */
531 SSLeay_add_ssl_algorithms ();
532 meth = SSLv2_client_method ();
533 SSL_load_error_strings ();
534 if ((ctx = SSL_CTX_new (meth)) == NULL)
535 {
536 printf (_("ERROR: Cannot create SSL context.\n"));
537 return STATE_CRITICAL;
538 }
540 /* Initialize alarm signal handling */
541 signal (SIGALRM, socket_timeout_alarm_handler);
543 /* Set socket timeout */
544 alarm (socket_timeout);
546 /* Save start time */
547 time (&start_time);
549 /* Make TCP connection */
550 if (my_tcp_connect (server_address, server_port, &sd) == STATE_OK && was_refused == FALSE)
551 {
552 /* Do the SSL handshake */
553 if ((ssl = SSL_new (ctx)) != NULL)
554 {
555 SSL_set_fd (ssl, sd);
556 if (SSL_connect (ssl) != -1)
557 return OK;
558 ERR_print_errors_fp (stderr);
559 }
560 else
561 {
562 printf (_("ERROR: Cannot initiate SSL handshake.\n"));
563 }
564 SSL_free (ssl);
565 }
567 SSL_CTX_free (ctx);
568 close (sd);
570 return STATE_CRITICAL;
571 }
572 #endif
576 int
577 my_recv (void)
578 {
579 int i;
581 #ifdef HAVE_SSL
582 if (use_ssl) {
583 i = SSL_read (ssl, buffer, MAXBUF - 1);
584 }
585 else {
586 #endif
587 i = read (sd, buffer, MAXBUF - 1);
588 #ifdef HAVE_SSL
589 }
590 #endif
592 return i;
593 }
599 \f
600 void
601 print_help (void)
602 {
603 print_revision (progname, revision);
605 printf (_("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"));
606 printf (_(COPYRIGHT), copyright, email);
608 printf (_("This plugin tests %s connections with the specified host.\n\n"),
609 SERVICE);
611 print_usage ();
613 printf (_(UT_HELP_VRSN));
615 printf (_(UT_HOST_PORT), 'p', "none");
617 printf (_(UT_IPv46));
619 printf (_("\
620 -s, --send=STRING\n\
621 String to send to the server\n\
622 -e, --expect=STRING\n\
623 String to expect in server response\n\
624 -q, --quit=STRING\n\
625 String to send server to initiate a clean close of the connection\n"));
627 printf (_("\
628 -r, --refuse=ok|warn|crit\n\
629 Accept tcp refusals with states ok, warn, crit (default: crit)\n\
630 -j, --jail\n\
631 Hide output from TCP socket\n\
632 -m, --maxbytes=INTEGER\n\
633 Close connection once more than this number of bytes are received\n\
634 -d, --delay=INTEGER\n\
635 Seconds to wait between sending string and polling for response\n"));
637 printf (_(UT_WARN_CRIT));
639 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
641 printf (_(UT_VERBOSE));
643 printf (_(UT_SUPPORT));
644 }
649 void
650 print_usage (void)
651 {
652 printf (_("\
653 Usage: %s -H host -p port [-w <warning time>] [-c <critical time>]\n\
654 [-s <send string>] [-e <expect string>] [-q <quit string>]\n\
655 [-m <maximum bytes>] [-d <delay>] [-t <timeout seconds>]\n\
656 [-r <refuse state>] [-v] [-4|-6] [-j]\n"), progname);
657 printf (" %s (-h|--help)\n", progname);
658 printf (" %s (-V|--version)\n", progname);
659 }