summaryrefslogtreecommitdiffstats
path: root/plugins/check_http.c
diff options
context:
space:
mode:
authorRincewindsHat <12514511+RincewindsHat@users.noreply.github.com>2023-09-18 20:59:46 (GMT)
committerRincewindsHat <12514511+RincewindsHat@users.noreply.github.com>2023-09-18 20:59:46 (GMT)
commit0e70e81133c25274fe2dd2309556b41357dd759b (patch)
tree9a680b36788ee1ad4e7ecc5ccfeb4494db9fdc72 /plugins/check_http.c
parentce355c80cf6054bfa5e1dcf81f9e2183ef963ee1 (diff)
parent2ddc75e69db5a3dd379c896d8420c9af20ec1cee (diff)
downloadmonitoring-plugins-0e70e81133c25274fe2dd2309556b41357dd759b.tar.gz
Merge branch 'master' into mysql_detect_mysqldumprefs/pull/1718/head
Diffstat (limited to 'plugins/check_http.c')
-rw-r--r--plugins/check_http.c374
1 files changed, 266 insertions, 108 deletions
diff --git a/plugins/check_http.c b/plugins/check_http.c
index 34fb4f0..718c8ee 100644
--- a/plugins/check_http.c
+++ b/plugins/check_http.c
@@ -31,13 +31,14 @@
31* 31*
32*****************************************************************************/ 32*****************************************************************************/
33 33
34/* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
35
36const char *progname = "check_http"; 34const char *progname = "check_http";
37const char *copyright = "1999-2013"; 35const char *copyright = "1999-2022";
38const char *email = "devel@monitoring-plugins.org"; 36const char *email = "devel@monitoring-plugins.org";
39 37
38// Do NOT sort those headers, it will break the build
39// TODO: Fix this
40#include "common.h" 40#include "common.h"
41#include "base64.h"
41#include "netutils.h" 42#include "netutils.h"
42#include "utils.h" 43#include "utils.h"
43#include "base64.h" 44#include "base64.h"
@@ -52,11 +53,13 @@ enum {
52 MAX_IPV4_HOSTLENGTH = 255, 53 MAX_IPV4_HOSTLENGTH = 255,
53 HTTP_PORT = 80, 54 HTTP_PORT = 80,
54 HTTPS_PORT = 443, 55 HTTPS_PORT = 443,
55 MAX_PORT = 65535 56 MAX_PORT = 65535,
57 DEFAULT_MAX_REDIRS = 15
56}; 58};
57 59
58#ifdef HAVE_SSL 60#ifdef HAVE_SSL
59int check_cert = FALSE; 61bool check_cert = false;
62bool continue_after_check_cert = false;
60int ssl_version = 0; 63int ssl_version = 0;
61int days_till_exp_warn, days_till_exp_crit; 64int days_till_exp_warn, days_till_exp_crit;
62char *randbuff; 65char *randbuff;
@@ -67,7 +70,7 @@ X509 *server_cert;
67# define my_recv(buf, len) read(sd, buf, len) 70# define my_recv(buf, len) read(sd, buf, len)
68# define my_send(buf, len) send(sd, buf, len, 0) 71# define my_send(buf, len) send(sd, buf, len, 0)
69#endif /* HAVE_SSL */ 72#endif /* HAVE_SSL */
70int no_body = FALSE; 73bool no_body = false;
71int maximum_age = -1; 74int maximum_age = -1;
72 75
73enum { 76enum {
@@ -89,7 +92,7 @@ struct timeval tv_temp;
89#define HTTP_URL "/" 92#define HTTP_URL "/"
90#define CRLF "\r\n" 93#define CRLF "\r\n"
91 94
92int specify_port = FALSE; 95bool specify_port = false;
93int server_port = HTTP_PORT; 96int server_port = HTTP_PORT;
94int virtual_port = 0; 97int virtual_port = 0;
95char server_port_text[6] = ""; 98char server_port_text[6] = "";
@@ -104,28 +107,26 @@ int server_expect_yn = 0;
104char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT; 107char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
105char header_expect[MAX_INPUT_BUFFER] = ""; 108char header_expect[MAX_INPUT_BUFFER] = "";
106char string_expect[MAX_INPUT_BUFFER] = ""; 109char string_expect[MAX_INPUT_BUFFER] = "";
107char output_header_search[30] = "";
108char output_string_search[30] = "";
109char *warning_thresholds = NULL; 110char *warning_thresholds = NULL;
110char *critical_thresholds = NULL; 111char *critical_thresholds = NULL;
111thresholds *thlds; 112thresholds *thlds;
112char user_auth[MAX_INPUT_BUFFER] = ""; 113char user_auth[MAX_INPUT_BUFFER] = "";
113char proxy_auth[MAX_INPUT_BUFFER] = ""; 114char proxy_auth[MAX_INPUT_BUFFER] = "";
114int display_html = FALSE; 115bool display_html = false;
115char **http_opt_headers; 116char **http_opt_headers;
116int http_opt_headers_count = 0; 117int http_opt_headers_count = 0;
117int onredirect = STATE_OK; 118int onredirect = STATE_OK;
118int followsticky = STICKY_NONE; 119int followsticky = STICKY_NONE;
119int use_ssl = FALSE; 120bool use_ssl = false;
120int use_sni = FALSE; 121bool use_sni = false;
121int verbose = FALSE; 122bool verbose = false;
122int show_extended_perfdata = FALSE; 123bool show_extended_perfdata = false;
123int show_body = FALSE; 124bool show_body = false;
124int sd; 125int sd;
125int min_page_len = 0; 126int min_page_len = 0;
126int max_page_len = 0; 127int max_page_len = 0;
127int redir_depth = 0; 128int redir_depth = 0;
128int max_depth = 15; 129int max_depth = DEFAULT_MAX_REDIRS;
129char *http_method; 130char *http_method;
130char *http_method_proxy; 131char *http_method_proxy;
131char *http_post_data; 132char *http_post_data;
@@ -134,10 +135,11 @@ char buffer[MAX_INPUT_BUFFER];
134char *client_cert = NULL; 135char *client_cert = NULL;
135char *client_privkey = NULL; 136char *client_privkey = NULL;
136 137
137int process_arguments (int, char **); 138// Forward function declarations
139bool process_arguments (int, char **);
138int check_http (void); 140int check_http (void);
139void redir (char *pos, char *status_line); 141void redir (char *pos, char *status_line);
140int server_type_check(const char *type); 142bool server_type_check(const char *type);
141int server_port_check(int ssl_flag); 143int server_port_check(int ssl_flag);
142char *perfd_time (double microsec); 144char *perfd_time (double microsec);
143char *perfd_time_connect (double microsec); 145char *perfd_time_connect (double microsec);
@@ -148,6 +150,7 @@ char *perfd_time_transfer (double microsec);
148char *perfd_size (int page_len); 150char *perfd_size (int page_len);
149void print_help (void); 151void print_help (void);
150void print_usage (void); 152void print_usage (void);
153char *unchunk_content(const char *content);
151 154
152int 155int
153main (int argc, char **argv) 156main (int argc, char **argv)
@@ -167,10 +170,10 @@ main (int argc, char **argv)
167 /* Parse extra opts if any */ 170 /* Parse extra opts if any */
168 argv=np_extra_opts (&argc, argv, progname); 171 argv=np_extra_opts (&argc, argv, progname);
169 172
170 if (process_arguments (argc, argv) == ERROR) 173 if (process_arguments (argc, argv) == false)
171 usage4 (_("Could not parse arguments")); 174 usage4 (_("Could not parse arguments"));
172 175
173 if (display_html == TRUE) 176 if (display_html == true)
174 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 177 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
175 use_ssl ? "https" : "http", host_name ? host_name : server_address, 178 use_ssl ? "https" : "http", host_name ? host_name : server_address,
176 server_port, server_url); 179 server_port, server_url);
@@ -193,9 +196,11 @@ test_file (char *path)
193 usage2 (_("file does not exist or is not readable"), path); 196 usage2 (_("file does not exist or is not readable"), path);
194} 197}
195 198
196/* process command-line arguments */ 199/*
197int 200 * process command-line arguments
198process_arguments (int argc, char **argv) 201 * returns true on success, false otherwise
202 */
203bool process_arguments (int argc, char **argv)
199{ 204{
200 int c = 1; 205 int c = 1;
201 char *p; 206 char *p;
@@ -203,7 +208,9 @@ process_arguments (int argc, char **argv)
203 208
204 enum { 209 enum {
205 INVERT_REGEX = CHAR_MAX + 1, 210 INVERT_REGEX = CHAR_MAX + 1,
206 SNI_OPTION 211 SNI_OPTION,
212 MAX_REDIRS_OPTION,
213 CONTINUE_AFTER_CHECK_CERT
207 }; 214 };
208 215
209 int option = 0; 216 int option = 0;
@@ -231,6 +238,7 @@ process_arguments (int argc, char **argv)
231 {"certificate", required_argument, 0, 'C'}, 238 {"certificate", required_argument, 0, 'C'},
232 {"client-cert", required_argument, 0, 'J'}, 239 {"client-cert", required_argument, 0, 'J'},
233 {"private-key", required_argument, 0, 'K'}, 240 {"private-key", required_argument, 0, 'K'},
241 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
234 {"useragent", required_argument, 0, 'A'}, 242 {"useragent", required_argument, 0, 'A'},
235 {"header", required_argument, 0, 'k'}, 243 {"header", required_argument, 0, 'k'},
236 {"no-body", no_argument, 0, 'N'}, 244 {"no-body", no_argument, 0, 'N'},
@@ -242,11 +250,12 @@ process_arguments (int argc, char **argv)
242 {"use-ipv6", no_argument, 0, '6'}, 250 {"use-ipv6", no_argument, 0, '6'},
243 {"extended-perfdata", no_argument, 0, 'E'}, 251 {"extended-perfdata", no_argument, 0, 'E'},
244 {"show-body", no_argument, 0, 'B'}, 252 {"show-body", no_argument, 0, 'B'},
253 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
245 {0, 0, 0, 0} 254 {0, 0, 0, 0}
246 }; 255 };
247 256
248 if (argc < 2) 257 if (argc < 2)
249 return ERROR; 258 return false;
250 259
251 for (c = 1; c < argc; c++) { 260 for (c = 1; c < argc; c++) {
252 if (strcmp ("-to", argv[c]) == 0) 261 if (strcmp ("-to", argv[c]) == 0)
@@ -302,10 +311,10 @@ process_arguments (int argc, char **argv)
302 /* xasprintf (&http_opt_headers, "%s", optarg); */ 311 /* xasprintf (&http_opt_headers, "%s", optarg); */
303 break; 312 break;
304 case 'L': /* show html link */ 313 case 'L': /* show html link */
305 display_html = TRUE; 314 display_html = true;
306 break; 315 break;
307 case 'n': /* do not show html link */ 316 case 'n': /* do not show html link */
308 display_html = FALSE; 317 display_html = false;
309 break; 318 break;
310 case 'C': /* Check SSL cert validity */ 319 case 'C': /* Check SSL cert validity */
311#ifdef HAVE_SSL 320#ifdef HAVE_SSL
@@ -326,9 +335,14 @@ process_arguments (int argc, char **argv)
326 usage2 (_("Invalid certificate expiration period"), optarg); 335 usage2 (_("Invalid certificate expiration period"), optarg);
327 days_till_exp_warn = atoi (optarg); 336 days_till_exp_warn = atoi (optarg);
328 } 337 }
329 check_cert = TRUE; 338 check_cert = true;
330 goto enable_ssl; 339 goto enable_ssl;
331#endif 340#endif
341 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
342#ifdef HAVE_SSL
343 continue_after_check_cert = true;
344 break;
345#endif
332 case 'J': /* use client certificate */ 346 case 'J': /* use client certificate */
333#ifdef HAVE_SSL 347#ifdef HAVE_SSL
334 test_file(optarg); 348 test_file(optarg);
@@ -346,7 +360,7 @@ process_arguments (int argc, char **argv)
346 enable_ssl: 360 enable_ssl:
347 /* ssl_version initialized to 0 as a default. Only set if it's non-zero. This helps when we include multiple 361 /* ssl_version initialized to 0 as a default. Only set if it's non-zero. This helps when we include multiple
348 parameters, like -S and -C combinations */ 362 parameters, like -S and -C combinations */
349 use_ssl = TRUE; 363 use_ssl = true;
350 if (c=='S' && optarg != NULL) { 364 if (c=='S' && optarg != NULL) {
351 int got_plus = strchr(optarg, '+') != NULL; 365 int got_plus = strchr(optarg, '+') != NULL;
352 366
@@ -363,7 +377,7 @@ process_arguments (int argc, char **argv)
363 else 377 else
364 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with optional '+' suffix)")); 378 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with optional '+' suffix)"));
365 } 379 }
366 if (specify_port == FALSE) 380 if (specify_port == false)
367 server_port = HTTPS_PORT; 381 server_port = HTTPS_PORT;
368#else 382#else
369 /* -C -J and -K fall through to here without SSL */ 383 /* -C -J and -K fall through to here without SSL */
@@ -371,8 +385,15 @@ process_arguments (int argc, char **argv)
371#endif 385#endif
372 break; 386 break;
373 case SNI_OPTION: 387 case SNI_OPTION:
374 use_sni = TRUE; 388 use_sni = true;
375 break; 389 break;
390 case MAX_REDIRS_OPTION:
391 if (!is_intnonneg (optarg))
392 usage2 (_("Invalid max_redirs count"), optarg);
393 else {
394 max_depth = atoi (optarg);
395 }
396 break;
376 case 'f': /* onredirect */ 397 case 'f': /* onredirect */
377 if (!strcmp (optarg, "stickyport")) 398 if (!strcmp (optarg, "stickyport"))
378 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT; 399 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT;
@@ -402,7 +423,7 @@ process_arguments (int argc, char **argv)
402 host_name_length = strlen (host_name) - strlen (p) - 1; 423 host_name_length = strlen (host_name) - strlen (p) - 1;
403 free (host_name); 424 free (host_name);
404 host_name = strndup (optarg, host_name_length); 425 host_name = strndup (optarg, host_name_length);
405 if (specify_port == FALSE) 426 if (specify_port == false)
406 server_port = virtual_port; 427 server_port = virtual_port;
407 } 428 }
408 } else if ((p = strchr (host_name, ':')) != NULL 429 } else if ((p = strchr (host_name, ':')) != NULL
@@ -412,7 +433,7 @@ process_arguments (int argc, char **argv)
412 host_name_length = strlen (host_name) - strlen (p) - 1; 433 host_name_length = strlen (host_name) - strlen (p) - 1;
413 free (host_name); 434 free (host_name);
414 host_name = strndup (optarg, host_name_length); 435 host_name = strndup (optarg, host_name_length);
415 if (specify_port == FALSE) 436 if (specify_port == false)
416 server_port = virtual_port; 437 server_port = virtual_port;
417 } 438 }
418 break; 439 break;
@@ -428,7 +449,7 @@ process_arguments (int argc, char **argv)
428 usage2 (_("Invalid port number"), optarg); 449 usage2 (_("Invalid port number"), optarg);
429 else { 450 else {
430 server_port = atoi (optarg); 451 server_port = atoi (optarg);
431 specify_port = TRUE; 452 specify_port = true;
432 } 453 }
433 break; 454 break;
434 case 'a': /* authorization info */ 455 case 'a': /* authorization info */
@@ -477,6 +498,7 @@ process_arguments (int argc, char **argv)
477 break; 498 break;
478 case 'R': /* regex */ 499 case 'R': /* regex */
479 cflags |= REG_ICASE; 500 cflags |= REG_ICASE;
501 // fall through
480 case 'r': /* regex */ 502 case 'r': /* regex */
481 strncpy (regexp, optarg, MAX_RE_SIZE - 1); 503 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
482 regexp[MAX_RE_SIZE - 1] = 0; 504 regexp[MAX_RE_SIZE - 1] = 0;
@@ -484,7 +506,7 @@ process_arguments (int argc, char **argv)
484 if (errcode != 0) { 506 if (errcode != 0) {
485 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 507 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
486 printf (_("Could Not Compile Regular Expression: %s"), errbuf); 508 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
487 return ERROR; 509 return false;
488 } 510 }
489 break; 511 break;
490 case INVERT_REGEX: 512 case INVERT_REGEX:
@@ -501,7 +523,7 @@ process_arguments (int argc, char **argv)
501#endif 523#endif
502 break; 524 break;
503 case 'v': /* verbose */ 525 case 'v': /* verbose */
504 verbose = TRUE; 526 verbose = true;
505 break; 527 break;
506 case 'm': /* min_page_length */ 528 case 'm': /* min_page_length */
507 { 529 {
@@ -526,7 +548,7 @@ process_arguments (int argc, char **argv)
526 break; 548 break;
527 } 549 }
528 case 'N': /* no-body */ 550 case 'N': /* no-body */
529 no_body = TRUE; 551 no_body = true;
530 break; 552 break;
531 case 'M': /* max-age */ 553 case 'M': /* max-age */
532 { 554 {
@@ -547,10 +569,10 @@ process_arguments (int argc, char **argv)
547 } 569 }
548 break; 570 break;
549 case 'E': /* show extended perfdata */ 571 case 'E': /* show extended perfdata */
550 show_extended_perfdata = TRUE; 572 show_extended_perfdata = true;
551 break; 573 break;
552 case 'B': /* print body content after status line */ 574 case 'B': /* print body content after status line */
553 show_body = TRUE; 575 show_body = true;
554 break; 576 break;
555 } 577 }
556 } 578 }
@@ -587,7 +609,7 @@ process_arguments (int argc, char **argv)
587 if (virtual_port == 0) 609 if (virtual_port == 0)
588 virtual_port = server_port; 610 virtual_port = server_port;
589 611
590 return TRUE; 612 return true;
591} 613}
592 614
593 615
@@ -927,7 +949,7 @@ check_http (void)
927 /* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */ 949 /* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */
928 950
929 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0 951 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0
930 && host_name != NULL && use_ssl == TRUE) { 952 && host_name != NULL && use_ssl == true) {
931 953
932 if (verbose) printf ("Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d\n", server_address, server_port, host_name, HTTPS_PORT); 954 if (verbose) printf ("Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d\n", server_address, server_port, host_name, HTTPS_PORT);
933 asprintf (&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT, user_agent); 955 asprintf (&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT, user_agent);
@@ -961,7 +983,7 @@ check_http (void)
961 } 983 }
962#ifdef HAVE_SSL 984#ifdef HAVE_SSL
963 elapsed_time_connect = (double)microsec_connect / 1.0e6; 985 elapsed_time_connect = (double)microsec_connect / 1.0e6;
964 if (use_ssl == TRUE) { 986 if (use_ssl == true) {
965 gettimeofday (&tv_temp, NULL); 987 gettimeofday (&tv_temp, NULL);
966 result = np_net_ssl_init_with_hostname_version_and_cert(sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey); 988 result = np_net_ssl_init_with_hostname_version_and_cert(sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey);
967 if (verbose) printf ("SSL initialized\n"); 989 if (verbose) printf ("SSL initialized\n");
@@ -969,17 +991,19 @@ check_http (void)
969 die (STATE_CRITICAL, NULL); 991 die (STATE_CRITICAL, NULL);
970 microsec_ssl = deltime (tv_temp); 992 microsec_ssl = deltime (tv_temp);
971 elapsed_time_ssl = (double)microsec_ssl / 1.0e6; 993 elapsed_time_ssl = (double)microsec_ssl / 1.0e6;
972 if (check_cert == TRUE) { 994 if (check_cert == true) {
973 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 995 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit);
974 if (sd) close(sd); 996 if (continue_after_check_cert == false) {
975 np_net_ssl_cleanup(); 997 if (sd) close(sd);
976 return result; 998 np_net_ssl_cleanup();
999 return result;
1000 }
977 } 1001 }
978 } 1002 }
979#endif /* HAVE_SSL */ 1003#endif /* HAVE_SSL */
980 1004
981 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0 1005 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0
982 && host_name != NULL && use_ssl == TRUE) 1006 && host_name != NULL && use_ssl == true)
983 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method_proxy, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent); 1007 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method_proxy, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
984 else 1008 else
985 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent); 1009 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
@@ -1007,10 +1031,10 @@ check_http (void)
1007 * 14.23). Some server applications/configurations cause trouble if the 1031 * 14.23). Some server applications/configurations cause trouble if the
1008 * (default) port is explicitly specified in the "Host:" header line. 1032 * (default) port is explicitly specified in the "Host:" header line.
1009 */ 1033 */
1010 if ((use_ssl == FALSE && virtual_port == HTTP_PORT) || 1034 if ((use_ssl == false && virtual_port == HTTP_PORT) ||
1011 (use_ssl == TRUE && virtual_port == HTTPS_PORT) || 1035 (use_ssl == true && virtual_port == HTTPS_PORT) ||
1012 (server_address != NULL && strcmp(http_method, "CONNECT") == 0 1036 (server_address != NULL && strcmp(http_method, "CONNECT") == 0
1013 && host_name != NULL && use_ssl == TRUE)) 1037 && host_name != NULL && use_ssl == true))
1014 xasprintf (&buf, "%sHost: %s\r\n", buf, host_name); 1038 xasprintf (&buf, "%sHost: %s\r\n", buf, host_name);
1015 else 1039 else
1016 xasprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, virtual_port); 1040 xasprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, virtual_port);
@@ -1050,9 +1074,8 @@ check_http (void)
1050 } 1074 }
1051 1075
1052 xasprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data)); 1076 xasprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
1053 xasprintf (&buf, "%s%s%s", buf, http_post_data, CRLF); 1077 xasprintf (&buf, "%s%s", buf, http_post_data);
1054 } 1078 } else {
1055 else {
1056 /* or just a newline so the server knows we're done with the request */ 1079 /* or just a newline so the server knows we're done with the request */
1057 xasprintf (&buf, "%s%s", buf, CRLF); 1080 xasprintf (&buf, "%s%s", buf, CRLF);
1058 } 1081 }
@@ -1076,9 +1099,14 @@ check_http (void)
1076 *pos = ' '; 1099 *pos = ' ';
1077 } 1100 }
1078 buffer[i] = '\0'; 1101 buffer[i] = '\0';
1079 xasprintf (&full_page_new, "%s%s", full_page, buffer); 1102
1080 free (full_page); 1103 if ((full_page_new = realloc(full_page, pagesize + i + 1)) == NULL)
1104 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate memory for full_page\n"));
1105
1106 memmove(&full_page_new[pagesize], buffer, i + 1);
1107
1081 full_page = full_page_new; 1108 full_page = full_page_new;
1109
1082 pagesize += i; 1110 pagesize += i;
1083 1111
1084 if (no_body && document_headers_done (full_page)) { 1112 if (no_body && document_headers_done (full_page)) {
@@ -1090,25 +1118,7 @@ check_http (void)
1090 elapsed_time_transfer = (double)microsec_transfer / 1.0e6; 1118 elapsed_time_transfer = (double)microsec_transfer / 1.0e6;
1091 1119
1092 if (i < 0 && errno != ECONNRESET) { 1120 if (i < 0 && errno != ECONNRESET) {
1093#ifdef HAVE_SSL 1121 die(STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
1094 /*
1095 if (use_ssl) {
1096 sslerr=SSL_get_error(ssl, i);
1097 if ( sslerr == SSL_ERROR_SSL ) {
1098 die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
1099 } else {
1100 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
1101 }
1102 }
1103 else {
1104 */
1105#endif
1106 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
1107#ifdef HAVE_SSL
1108 /* XXX
1109 }
1110 */
1111#endif
1112 } 1122 }
1113 1123
1114 /* return a CRITICAL status if we couldn't read any data */ 1124 /* return a CRITICAL status if we couldn't read any data */
@@ -1233,32 +1243,73 @@ check_http (void)
1233 } 1243 }
1234 1244
1235 /* Page and Header content checks go here */ 1245 /* Page and Header content checks go here */
1236 if (strlen (header_expect)) { 1246 if (strlen(header_expect) > 0) {
1237 if (!strstr (header, header_expect)) { 1247 if (strstr(header, header_expect) == NULL) {
1238 strncpy(&output_header_search[0],header_expect,sizeof(output_header_search)); 1248 // We did not find the header, the rest is for building the output and setting the state
1239 if(output_header_search[sizeof(output_header_search)-1]!='\0') { 1249 char output_header_search[30] = "";
1240 bcopy("...",&output_header_search[sizeof(output_header_search)-4],4); 1250
1251 strncpy(&output_header_search[0], header_expect,
1252 sizeof(output_header_search));
1253
1254 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1255 bcopy("...",
1256 &output_header_search[sizeof(output_header_search) - 4],
1257 4);
1241 } 1258 }
1242 xasprintf (&msg, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg, output_header_search, use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); 1259
1260 xasprintf (&msg,
1261 _("%sheader '%s' not found on '%s://%s:%d%s', "),
1262 msg,
1263 output_header_search, use_ssl ? "https" : "http",
1264 host_name ? host_name : server_address, server_port,
1265 server_url);
1266
1243 result = STATE_CRITICAL; 1267 result = STATE_CRITICAL;
1244 } 1268 }
1245 } 1269 }
1246 1270
1271 // At this point we should test if the content is chunked and unchunk it, so
1272 // it can be searched (and possibly printed)
1273 const char *chunked_header_regex_string = "Transfer-Encoding: *chunked *";
1274 regex_t chunked_header_regex;
1247 1275
1248 if (strlen (string_expect)) { 1276 if (regcomp(&chunked_header_regex, chunked_header_regex_string, REG_ICASE)) {
1249 if (!strstr (page, string_expect)) { 1277 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to compile chunked_header_regex regex");
1250 strncpy(&output_string_search[0],string_expect,sizeof(output_string_search)); 1278 }
1251 if(output_string_search[sizeof(output_string_search)-1]!='\0') { 1279
1252 bcopy("...",&output_string_search[sizeof(output_string_search)-4],4); 1280 regmatch_t chre_pmatch[1]; // We actually do not care about this, since we only want to know IF it was found
1281
1282 if (!no_body && regexec(&chunked_header_regex, header, 1, chre_pmatch, 0) == 0) {
1283 if (verbose) {
1284 printf("Found chunked content\n");
1285 }
1286 // We actually found the chunked header
1287 char *tmp = unchunk_content(page);
1288 if (tmp == NULL) {
1289 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to unchunk message body");
1290 }
1291 page = tmp;
1292 }
1293
1294 if (strlen(string_expect) > 0) {
1295 if (!strstr(page, string_expect)) {
1296 // We found the string the body, the rest is for building the output
1297 char output_string_search[30] = "";
1298 strncpy(&output_string_search[0], string_expect,
1299 sizeof(output_string_search));
1300 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1301 bcopy("...", &output_string_search[sizeof(output_string_search) - 4],
1302 4);
1253 } 1303 }
1254 xasprintf (&msg, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search, use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); 1304 xasprintf (&msg, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search, use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url);
1255 result = STATE_CRITICAL; 1305 result = STATE_CRITICAL;
1256 } 1306 }
1257 } 1307 }
1258 1308
1259 if (strlen (regexp)) { 1309 if (strlen(regexp) > 0) {
1260 errcode = regexec (&preg, page, REGS, pmatch, 0); 1310 errcode = regexec(&preg, page, REGS, pmatch, 0);
1261 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) { 1311 if ((errcode == 0 && invert_regex == 0) ||
1312 (errcode == REG_NOMATCH && invert_regex == 1)) {
1262 /* OK - No-op to avoid changing the logic around it */ 1313 /* OK - No-op to avoid changing the logic around it */
1263 result = max_state_alt(STATE_OK, result); 1314 result = max_state_alt(STATE_OK, result);
1264 } 1315 }
@@ -1310,7 +1361,7 @@ check_http (void)
1310 perfd_time (elapsed_time), 1361 perfd_time (elapsed_time),
1311 perfd_size (page_len), 1362 perfd_size (page_len),
1312 perfd_time_connect (elapsed_time_connect), 1363 perfd_time_connect (elapsed_time_connect),
1313 use_ssl == TRUE ? perfd_time_ssl (elapsed_time_ssl) : "", 1364 use_ssl == true ? perfd_time_ssl (elapsed_time_ssl) : "",
1314 perfd_time_headers (elapsed_time_headers), 1365 perfd_time_headers (elapsed_time_headers),
1315 perfd_time_firstbyte (elapsed_time_firstbyte), 1366 perfd_time_firstbyte (elapsed_time_firstbyte),
1316 perfd_time_transfer (elapsed_time_transfer)); 1367 perfd_time_transfer (elapsed_time_transfer));
@@ -1332,7 +1383,94 @@ check_http (void)
1332 return STATE_UNKNOWN; 1383 return STATE_UNKNOWN;
1333} 1384}
1334 1385
1386/* Receivces a pointer to the beginning of the body of a HTTP message
1387 * which is chunked and returns a pointer to a freshly allocated memory
1388 * region containing the unchunked body or NULL if something failed.
1389 * The result must be freed by the caller.
1390 */
1391char *unchunk_content(const char *content) {
1392 // https://en.wikipedia.org/wiki/Chunked_transfer_encoding
1393 // https://www.rfc-editor.org/rfc/rfc7230#section-4.1
1394 char *result = NULL;
1395 char *start_of_chunk;
1396 char* end_of_chunk;
1397 long size_of_chunk;
1398 const char *pointer = content;
1399 char *endptr;
1400 long length_of_chunk = 0;
1401 size_t overall_size = 0;
1402
1403 while (true) {
1404 size_of_chunk = strtol(pointer, &endptr, 16);
1405 if (size_of_chunk == LONG_MIN || size_of_chunk == LONG_MAX) {
1406 // Apparently underflow or overflow, should not happen
1407 if (verbose) {
1408 printf("Got an underflow or overflow from strtol at: %u\n", __LINE__);
1409 }
1410 return NULL;
1411 }
1412 if (endptr == pointer) {
1413 // Apparently this was not a number
1414 if (verbose) {
1415 printf("Chunked content did not start with a number at all (Line: %u)\n", __LINE__);
1416 }
1417 return NULL;
1418 }
1419
1420 // So, we got the length of the chunk
1421 if (*endptr == ';') {
1422 // Chunk extension starts here
1423 while (*endptr != '\r') {
1424 endptr++;
1425 }
1426 }
1427
1428 start_of_chunk = endptr + 2;
1429 end_of_chunk = start_of_chunk + size_of_chunk;
1430 length_of_chunk = (long)(end_of_chunk - start_of_chunk);
1431 pointer = end_of_chunk + 2; //Next number should be here
1432
1433 if (length_of_chunk == 0) {
1434 // Chunk length is 0, so this is the last one
1435 break;
1436 }
1437
1438 overall_size += length_of_chunk;
1439
1440 if (result == NULL) {
1441 // Size of the chunk plus the ending NULL byte
1442 result = (char *)malloc(length_of_chunk +1);
1443 if (result == NULL) {
1444 if (verbose) {
1445 printf("Failed to allocate memory for unchunked body\n");
1446 }
1447 return NULL;
1448 }
1449 } else {
1450 // Enlarge memory to the new size plus the ending NULL byte
1451 void *tmp = realloc(result, overall_size +1);
1452 if (tmp == NULL) {
1453 if (verbose) {
1454 printf("Failed to allocate memory for unchunked body\n");
1455 }
1456 return NULL;
1457 } else {
1458 result = tmp;
1459 }
1460 }
1461
1462 memcpy(result + (overall_size - size_of_chunk), start_of_chunk, size_of_chunk);
1463 }
1335 1464
1465 if (overall_size == 0 && result == NULL) {
1466 // We might just have received the end chunk without previous content, so result is never allocated
1467 result = calloc(1, sizeof(char));
1468 // No error handling here, we can only return NULL anyway
1469 } else {
1470 result[overall_size] = '\0';
1471 }
1472 return result;
1473}
1336 1474
1337/* per RFC 2396 */ 1475/* per RFC 2396 */
1338#define URI_HTTP "%5[HTPShtps]" 1476#define URI_HTTP "%5[HTPShtps]"
@@ -1343,7 +1481,9 @@ check_http (void)
1343#define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH 1481#define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1344#define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT 1482#define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1345#define HD4 URI_HTTP "://" URI_HOST 1483#define HD4 URI_HTTP "://" URI_HOST
1346#define HD5 URI_PATH 1484/* relative reference redirect like //www.site.org/test https://tools.ietf.org/html/rfc3986 */
1485#define HD5 "//" URI_HOST "/" URI_PATH
1486#define HD6 URI_PATH
1347 1487
1348void 1488void
1349redir (char *pos, char *status_line) 1489redir (char *pos, char *status_line)
@@ -1420,9 +1560,21 @@ redir (char *pos, char *status_line)
1420 use_ssl = server_type_check (type); 1560 use_ssl = server_type_check (type);
1421 i = server_port_check (use_ssl); 1561 i = server_port_check (use_ssl);
1422 } 1562 }
1563 /* URI_HTTP, URI_HOST, URI_PATH */
1564 else if (sscanf (pos, HD5, addr, url) == 2) {
1565 if(use_ssl){
1566 strcpy (type,"https");
1567 }
1568 else{
1569 strcpy (type, server_type);
1570 }
1571 xasprintf (&url, "/%s", url);
1572 use_ssl = server_type_check (type);
1573 i = server_port_check (use_ssl);
1574 }
1423 1575
1424 /* URI_PATH */ 1576 /* URI_PATH */
1425 else if (sscanf (pos, HD5, url) == 1) { 1577 else if (sscanf (pos, HD6, url) == 1) {
1426 /* relative url */ 1578 /* relative url */
1427 if ((url[0] != '/')) { 1579 if ((url[0] != '/')) {
1428 if ((x = strrchr(server_url, '/'))) 1580 if ((x = strrchr(server_url, '/')))
@@ -1491,13 +1643,13 @@ redir (char *pos, char *status_line)
1491} 1643}
1492 1644
1493 1645
1494int 1646bool
1495server_type_check (const char *type) 1647server_type_check (const char *type)
1496{ 1648{
1497 if (strcmp (type, "https")) 1649 if (strcmp (type, "https"))
1498 return FALSE; 1650 return false;
1499 else 1651 else
1500 return TRUE; 1652 return true;
1501} 1653}
1502 1654
1503int 1655int
@@ -1512,42 +1664,42 @@ server_port_check (int ssl_flag)
1512char *perfd_time (double elapsed_time) 1664char *perfd_time (double elapsed_time)
1513{ 1665{
1514 return fperfdata ("time", elapsed_time, "s", 1666 return fperfdata ("time", elapsed_time, "s",
1515 thlds->warning?TRUE:FALSE, thlds->warning?thlds->warning->end:0, 1667 thlds->warning?true:false, thlds->warning?thlds->warning->end:0,
1516 thlds->critical?TRUE:FALSE, thlds->critical?thlds->critical->end:0, 1668 thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
1517 TRUE, 0, TRUE, socket_timeout); 1669 true, 0, true, socket_timeout);
1518} 1670}
1519 1671
1520char *perfd_time_connect (double elapsed_time_connect) 1672char *perfd_time_connect (double elapsed_time_connect)
1521{ 1673{
1522 return fperfdata ("time_connect", elapsed_time_connect, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1674 return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1523} 1675}
1524 1676
1525char *perfd_time_ssl (double elapsed_time_ssl) 1677char *perfd_time_ssl (double elapsed_time_ssl)
1526{ 1678{
1527 return fperfdata ("time_ssl", elapsed_time_ssl, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1679 return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1528} 1680}
1529 1681
1530char *perfd_time_headers (double elapsed_time_headers) 1682char *perfd_time_headers (double elapsed_time_headers)
1531{ 1683{
1532 return fperfdata ("time_headers", elapsed_time_headers, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1684 return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1533} 1685}
1534 1686
1535char *perfd_time_firstbyte (double elapsed_time_firstbyte) 1687char *perfd_time_firstbyte (double elapsed_time_firstbyte)
1536{ 1688{
1537 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1689 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1538} 1690}
1539 1691
1540char *perfd_time_transfer (double elapsed_time_transfer) 1692char *perfd_time_transfer (double elapsed_time_transfer)
1541{ 1693{
1542 return fperfdata ("time_transfer", elapsed_time_transfer, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1694 return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1543} 1695}
1544 1696
1545char *perfd_size (int page_len) 1697char *perfd_size (int page_len)
1546{ 1698{
1547 return perfdata ("size", page_len, "B", 1699 return perfdata ("size", page_len, "B",
1548 (min_page_len>0?TRUE:FALSE), min_page_len, 1700 (min_page_len>0?true:false), min_page_len,
1549 (min_page_len>0?TRUE:FALSE), 0, 1701 (min_page_len>0?true:false), 0,
1550 TRUE, 0, FALSE, 0); 1702 true, 0, false, 0);
1551} 1703}
1552 1704
1553void 1705void
@@ -1598,7 +1750,11 @@ print_help (void)
1598 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 1750 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
1599 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]"); 1751 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
1600 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443")); 1752 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1601 printf (" %s\n", _("(when this option is used the URL is not checked.)")); 1753 printf (" %s\n", _("(when this option is used the URL is not checked by default. You can use"));
1754 printf (" %s\n", _(" --continue-after-certificate to override this behavior)"));
1755 printf (" %s\n", "--continue-after-certificate");
1756 printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check."));
1757 printf (" %s\n", _("Does nothing unless -C is used."));
1602 printf (" %s\n", "-J, --client-cert=FILE"); 1758 printf (" %s\n", "-J, --client-cert=FILE");
1603 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)")); 1759 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)"));
1604 printf (" %s\n", _("to be used in establishing the SSL session")); 1760 printf (" %s\n", _("to be used in establishing the SSL session"));
@@ -1657,9 +1813,11 @@ print_help (void)
1657 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>"); 1813 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>");
1658 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the")); 1814 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
1659 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same.")); 1815 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
1816 printf (" %s\n", "--max-redirs=INTEGER");
1817 printf (" %s", _("Maximal number of redirects (default: "));
1818 printf ("%d)\n", DEFAULT_MAX_REDIRS);
1660 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); 1819 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1661 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); 1820 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1662
1663 printf (UT_WARN_CRIT); 1821 printf (UT_WARN_CRIT);
1664 1822
1665 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 1823 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
@@ -1727,7 +1885,7 @@ print_usage (void)
1727 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname); 1885 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1728 printf (" [-J <client certificate file>] [-K <private key>]\n"); 1886 printf (" [-J <client certificate file>] [-K <private key>]\n");
1729 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); 1887 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
1730 printf (" [-b proxy_auth] [-f <ok|warning|critcal|follow|sticky|stickyport>]\n"); 1888 printf (" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport>]\n");
1731 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); 1889 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
1732 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); 1890 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
1733 printf (" [-A string] [-k string] [-S <version>] [--sni]\n"); 1891 printf (" [-A string] [-k string] [-S <version>] [--sni]\n");