summaryrefslogtreecommitdiffstats
path: root/plugins/check_http.c
diff options
context:
space:
mode:
authorLorenz <12514511+RincewindsHat@users.noreply.github.com>2023-01-09 16:55:10 +0100
committerGitHub <noreply@github.com>2023-01-09 16:55:10 +0100
commite0ada6f11a82ed6119836482b84c8ba5df491d8f (patch)
tree6ddcd5f7850169d82d88dca56a2e5c0dbda08b4e /plugins/check_http.c
parentc389aa4f918aab5cf181aa2cb9dec68b3bf34d4f (diff)
parent0899e41f5075d661153eb2c77ace1734a8f66bfa (diff)
downloadmonitoring-plugins-e0ada6f.tar.gz
Merge branch 'master' into rename_output_to_cmd_output
Diffstat (limited to 'plugins/check_http.c')
-rw-r--r--plugins/check_http.c329
1 files changed, 227 insertions, 102 deletions
diff --git a/plugins/check_http.c b/plugins/check_http.c
index f8ec853b..a9c22389 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"
@@ -57,8 +58,8 @@ enum {
57}; 58};
58 59
59#ifdef HAVE_SSL 60#ifdef HAVE_SSL
60int check_cert = FALSE; 61bool check_cert = false;
61int continue_after_check_cert = FALSE; 62bool continue_after_check_cert = false;
62int ssl_version = 0; 63int ssl_version = 0;
63int days_till_exp_warn, days_till_exp_crit; 64int days_till_exp_warn, days_till_exp_crit;
64char *randbuff; 65char *randbuff;
@@ -69,7 +70,7 @@ X509 *server_cert;
69# define my_recv(buf, len) read(sd, buf, len) 70# define my_recv(buf, len) read(sd, buf, len)
70# define my_send(buf, len) send(sd, buf, len, 0) 71# define my_send(buf, len) send(sd, buf, len, 0)
71#endif /* HAVE_SSL */ 72#endif /* HAVE_SSL */
72int no_body = FALSE; 73bool no_body = false;
73int maximum_age = -1; 74int maximum_age = -1;
74 75
75enum { 76enum {
@@ -91,7 +92,7 @@ struct timeval tv_temp;
91#define HTTP_URL "/" 92#define HTTP_URL "/"
92#define CRLF "\r\n" 93#define CRLF "\r\n"
93 94
94int specify_port = FALSE; 95bool specify_port = false;
95int server_port = HTTP_PORT; 96int server_port = HTTP_PORT;
96int virtual_port = 0; 97int virtual_port = 0;
97char server_port_text[6] = ""; 98char server_port_text[6] = "";
@@ -106,23 +107,21 @@ int server_expect_yn = 0;
106char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT; 107char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
107char header_expect[MAX_INPUT_BUFFER] = ""; 108char header_expect[MAX_INPUT_BUFFER] = "";
108char string_expect[MAX_INPUT_BUFFER] = ""; 109char string_expect[MAX_INPUT_BUFFER] = "";
109char output_header_search[30] = "";
110char output_string_search[30] = "";
111char *warning_thresholds = NULL; 110char *warning_thresholds = NULL;
112char *critical_thresholds = NULL; 111char *critical_thresholds = NULL;
113thresholds *thlds; 112thresholds *thlds;
114char user_auth[MAX_INPUT_BUFFER] = ""; 113char user_auth[MAX_INPUT_BUFFER] = "";
115char proxy_auth[MAX_INPUT_BUFFER] = ""; 114char proxy_auth[MAX_INPUT_BUFFER] = "";
116int display_html = FALSE; 115bool display_html = false;
117char **http_opt_headers; 116char **http_opt_headers;
118int http_opt_headers_count = 0; 117int http_opt_headers_count = 0;
119int onredirect = STATE_OK; 118int onredirect = STATE_OK;
120int followsticky = STICKY_NONE; 119int followsticky = STICKY_NONE;
121int use_ssl = FALSE; 120bool use_ssl = false;
122int use_sni = FALSE; 121bool use_sni = false;
123int verbose = FALSE; 122bool verbose = false;
124int show_extended_perfdata = FALSE; 123bool show_extended_perfdata = false;
125int show_body = FALSE; 124bool show_body = false;
126int sd; 125int sd;
127int min_page_len = 0; 126int min_page_len = 0;
128int max_page_len = 0; 127int max_page_len = 0;
@@ -136,10 +135,11 @@ char buffer[MAX_INPUT_BUFFER];
136char *client_cert = NULL; 135char *client_cert = NULL;
137char *client_privkey = NULL; 136char *client_privkey = NULL;
138 137
139int process_arguments (int, char **); 138// Forward function declarations
139bool process_arguments (int, char **);
140int check_http (void); 140int check_http (void);
141void redir (char *pos, char *status_line); 141void redir (char *pos, char *status_line);
142int server_type_check(const char *type); 142bool server_type_check(const char *type);
143int server_port_check(int ssl_flag); 143int server_port_check(int ssl_flag);
144char *perfd_time (double microsec); 144char *perfd_time (double microsec);
145char *perfd_time_connect (double microsec); 145char *perfd_time_connect (double microsec);
@@ -150,6 +150,7 @@ char *perfd_time_transfer (double microsec);
150char *perfd_size (int page_len); 150char *perfd_size (int page_len);
151void print_help (void); 151void print_help (void);
152void print_usage (void); 152void print_usage (void);
153char *unchunk_content(const char *content);
153 154
154int 155int
155main (int argc, char **argv) 156main (int argc, char **argv)
@@ -169,10 +170,10 @@ main (int argc, char **argv)
169 /* Parse extra opts if any */ 170 /* Parse extra opts if any */
170 argv=np_extra_opts (&argc, argv, progname); 171 argv=np_extra_opts (&argc, argv, progname);
171 172
172 if (process_arguments (argc, argv) == ERROR) 173 if (process_arguments (argc, argv) == false)
173 usage4 (_("Could not parse arguments")); 174 usage4 (_("Could not parse arguments"));
174 175
175 if (display_html == TRUE) 176 if (display_html == true)
176 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 177 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
177 use_ssl ? "https" : "http", host_name ? host_name : server_address, 178 use_ssl ? "https" : "http", host_name ? host_name : server_address,
178 server_port, server_url); 179 server_port, server_url);
@@ -195,9 +196,11 @@ test_file (char *path)
195 usage2 (_("file does not exist or is not readable"), path); 196 usage2 (_("file does not exist or is not readable"), path);
196} 197}
197 198
198/* process command-line arguments */ 199/*
199int 200 * process command-line arguments
200process_arguments (int argc, char **argv) 201 * returns true on succes, false otherwise
202 */
203bool process_arguments (int argc, char **argv)
201{ 204{
202 int c = 1; 205 int c = 1;
203 char *p; 206 char *p;
@@ -252,7 +255,7 @@ process_arguments (int argc, char **argv)
252 }; 255 };
253 256
254 if (argc < 2) 257 if (argc < 2)
255 return ERROR; 258 return false;
256 259
257 for (c = 1; c < argc; c++) { 260 for (c = 1; c < argc; c++) {
258 if (strcmp ("-to", argv[c]) == 0) 261 if (strcmp ("-to", argv[c]) == 0)
@@ -308,10 +311,10 @@ process_arguments (int argc, char **argv)
308 /* xasprintf (&http_opt_headers, "%s", optarg); */ 311 /* xasprintf (&http_opt_headers, "%s", optarg); */
309 break; 312 break;
310 case 'L': /* show html link */ 313 case 'L': /* show html link */
311 display_html = TRUE; 314 display_html = true;
312 break; 315 break;
313 case 'n': /* do not show html link */ 316 case 'n': /* do not show html link */
314 display_html = FALSE; 317 display_html = false;
315 break; 318 break;
316 case 'C': /* Check SSL cert validity */ 319 case 'C': /* Check SSL cert validity */
317#ifdef HAVE_SSL 320#ifdef HAVE_SSL
@@ -332,12 +335,12 @@ process_arguments (int argc, char **argv)
332 usage2 (_("Invalid certificate expiration period"), optarg); 335 usage2 (_("Invalid certificate expiration period"), optarg);
333 days_till_exp_warn = atoi (optarg); 336 days_till_exp_warn = atoi (optarg);
334 } 337 }
335 check_cert = TRUE; 338 check_cert = true;
336 goto enable_ssl; 339 goto enable_ssl;
337#endif 340#endif
338 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */ 341 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
339#ifdef HAVE_SSL 342#ifdef HAVE_SSL
340 continue_after_check_cert = TRUE; 343 continue_after_check_cert = true;
341 break; 344 break;
342#endif 345#endif
343 case 'J': /* use client certificate */ 346 case 'J': /* use client certificate */
@@ -357,7 +360,7 @@ process_arguments (int argc, char **argv)
357 enable_ssl: 360 enable_ssl:
358 /* 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
359 parameters, like -S and -C combinations */ 362 parameters, like -S and -C combinations */
360 use_ssl = TRUE; 363 use_ssl = true;
361 if (c=='S' && optarg != NULL) { 364 if (c=='S' && optarg != NULL) {
362 int got_plus = strchr(optarg, '+') != NULL; 365 int got_plus = strchr(optarg, '+') != NULL;
363 366
@@ -374,7 +377,7 @@ process_arguments (int argc, char **argv)
374 else 377 else
375 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)"));
376 } 379 }
377 if (specify_port == FALSE) 380 if (specify_port == false)
378 server_port = HTTPS_PORT; 381 server_port = HTTPS_PORT;
379#else 382#else
380 /* -C -J and -K fall through to here without SSL */ 383 /* -C -J and -K fall through to here without SSL */
@@ -382,7 +385,7 @@ process_arguments (int argc, char **argv)
382#endif 385#endif
383 break; 386 break;
384 case SNI_OPTION: 387 case SNI_OPTION:
385 use_sni = TRUE; 388 use_sni = true;
386 break; 389 break;
387 case MAX_REDIRS_OPTION: 390 case MAX_REDIRS_OPTION:
388 if (!is_intnonneg (optarg)) 391 if (!is_intnonneg (optarg))
@@ -420,7 +423,7 @@ process_arguments (int argc, char **argv)
420 host_name_length = strlen (host_name) - strlen (p) - 1; 423 host_name_length = strlen (host_name) - strlen (p) - 1;
421 free (host_name); 424 free (host_name);
422 host_name = strndup (optarg, host_name_length); 425 host_name = strndup (optarg, host_name_length);
423 if (specify_port == FALSE) 426 if (specify_port == false)
424 server_port = virtual_port; 427 server_port = virtual_port;
425 } 428 }
426 } else if ((p = strchr (host_name, ':')) != NULL 429 } else if ((p = strchr (host_name, ':')) != NULL
@@ -430,7 +433,7 @@ process_arguments (int argc, char **argv)
430 host_name_length = strlen (host_name) - strlen (p) - 1; 433 host_name_length = strlen (host_name) - strlen (p) - 1;
431 free (host_name); 434 free (host_name);
432 host_name = strndup (optarg, host_name_length); 435 host_name = strndup (optarg, host_name_length);
433 if (specify_port == FALSE) 436 if (specify_port == false)
434 server_port = virtual_port; 437 server_port = virtual_port;
435 } 438 }
436 break; 439 break;
@@ -446,7 +449,7 @@ process_arguments (int argc, char **argv)
446 usage2 (_("Invalid port number"), optarg); 449 usage2 (_("Invalid port number"), optarg);
447 else { 450 else {
448 server_port = atoi (optarg); 451 server_port = atoi (optarg);
449 specify_port = TRUE; 452 specify_port = true;
450 } 453 }
451 break; 454 break;
452 case 'a': /* authorization info */ 455 case 'a': /* authorization info */
@@ -502,7 +505,7 @@ process_arguments (int argc, char **argv)
502 if (errcode != 0) { 505 if (errcode != 0) {
503 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 506 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
504 printf (_("Could Not Compile Regular Expression: %s"), errbuf); 507 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
505 return ERROR; 508 return false;
506 } 509 }
507 break; 510 break;
508 case INVERT_REGEX: 511 case INVERT_REGEX:
@@ -519,7 +522,7 @@ process_arguments (int argc, char **argv)
519#endif 522#endif
520 break; 523 break;
521 case 'v': /* verbose */ 524 case 'v': /* verbose */
522 verbose = TRUE; 525 verbose = true;
523 break; 526 break;
524 case 'm': /* min_page_length */ 527 case 'm': /* min_page_length */
525 { 528 {
@@ -544,7 +547,7 @@ process_arguments (int argc, char **argv)
544 break; 547 break;
545 } 548 }
546 case 'N': /* no-body */ 549 case 'N': /* no-body */
547 no_body = TRUE; 550 no_body = true;
548 break; 551 break;
549 case 'M': /* max-age */ 552 case 'M': /* max-age */
550 { 553 {
@@ -565,10 +568,10 @@ process_arguments (int argc, char **argv)
565 } 568 }
566 break; 569 break;
567 case 'E': /* show extended perfdata */ 570 case 'E': /* show extended perfdata */
568 show_extended_perfdata = TRUE; 571 show_extended_perfdata = true;
569 break; 572 break;
570 case 'B': /* print body content after status line */ 573 case 'B': /* print body content after status line */
571 show_body = TRUE; 574 show_body = true;
572 break; 575 break;
573 } 576 }
574 } 577 }
@@ -605,7 +608,7 @@ process_arguments (int argc, char **argv)
605 if (virtual_port == 0) 608 if (virtual_port == 0)
606 virtual_port = server_port; 609 virtual_port = server_port;
607 610
608 return TRUE; 611 return true;
609} 612}
610 613
611 614
@@ -945,7 +948,7 @@ check_http (void)
945 /* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */ 948 /* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */
946 949
947 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0 950 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0
948 && host_name != NULL && use_ssl == TRUE) { 951 && host_name != NULL && use_ssl == true) {
949 952
950 if (verbose) printf ("Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d\n", server_address, server_port, host_name, HTTPS_PORT); 953 if (verbose) printf ("Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d\n", server_address, server_port, host_name, HTTPS_PORT);
951 asprintf (&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT, user_agent); 954 asprintf (&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT, user_agent);
@@ -979,7 +982,7 @@ check_http (void)
979 } 982 }
980#ifdef HAVE_SSL 983#ifdef HAVE_SSL
981 elapsed_time_connect = (double)microsec_connect / 1.0e6; 984 elapsed_time_connect = (double)microsec_connect / 1.0e6;
982 if (use_ssl == TRUE) { 985 if (use_ssl == true) {
983 gettimeofday (&tv_temp, NULL); 986 gettimeofday (&tv_temp, NULL);
984 result = np_net_ssl_init_with_hostname_version_and_cert(sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey); 987 result = np_net_ssl_init_with_hostname_version_and_cert(sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey);
985 if (verbose) printf ("SSL initialized\n"); 988 if (verbose) printf ("SSL initialized\n");
@@ -987,9 +990,9 @@ check_http (void)
987 die (STATE_CRITICAL, NULL); 990 die (STATE_CRITICAL, NULL);
988 microsec_ssl = deltime (tv_temp); 991 microsec_ssl = deltime (tv_temp);
989 elapsed_time_ssl = (double)microsec_ssl / 1.0e6; 992 elapsed_time_ssl = (double)microsec_ssl / 1.0e6;
990 if (check_cert == TRUE) { 993 if (check_cert == true) {
991 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 994 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit);
992 if (continue_after_check_cert == FALSE) { 995 if (continue_after_check_cert == false) {
993 if (sd) close(sd); 996 if (sd) close(sd);
994 np_net_ssl_cleanup(); 997 np_net_ssl_cleanup();
995 return result; 998 return result;
@@ -999,7 +1002,7 @@ check_http (void)
999#endif /* HAVE_SSL */ 1002#endif /* HAVE_SSL */
1000 1003
1001 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0 1004 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0
1002 && host_name != NULL && use_ssl == TRUE) 1005 && host_name != NULL && use_ssl == true)
1003 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); 1006 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);
1004 else 1007 else
1005 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent); 1008 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
@@ -1027,10 +1030,10 @@ check_http (void)
1027 * 14.23). Some server applications/configurations cause trouble if the 1030 * 14.23). Some server applications/configurations cause trouble if the
1028 * (default) port is explicitly specified in the "Host:" header line. 1031 * (default) port is explicitly specified in the "Host:" header line.
1029 */ 1032 */
1030 if ((use_ssl == FALSE && virtual_port == HTTP_PORT) || 1033 if ((use_ssl == false && virtual_port == HTTP_PORT) ||
1031 (use_ssl == TRUE && virtual_port == HTTPS_PORT) || 1034 (use_ssl == true && virtual_port == HTTPS_PORT) ||
1032 (server_address != NULL && strcmp(http_method, "CONNECT") == 0 1035 (server_address != NULL && strcmp(http_method, "CONNECT") == 0
1033 && host_name != NULL && use_ssl == TRUE)) 1036 && host_name != NULL && use_ssl == true))
1034 xasprintf (&buf, "%sHost: %s\r\n", buf, host_name); 1037 xasprintf (&buf, "%sHost: %s\r\n", buf, host_name);
1035 else 1038 else
1036 xasprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, virtual_port); 1039 xasprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, virtual_port);
@@ -1070,9 +1073,8 @@ check_http (void)
1070 } 1073 }
1071 1074
1072 xasprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data)); 1075 xasprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
1073 xasprintf (&buf, "%s%s%s", buf, http_post_data, CRLF); 1076 xasprintf (&buf, "%s%s", buf, http_post_data);
1074 } 1077 } else {
1075 else {
1076 /* or just a newline so the server knows we're done with the request */ 1078 /* or just a newline so the server knows we're done with the request */
1077 xasprintf (&buf, "%s%s", buf, CRLF); 1079 xasprintf (&buf, "%s%s", buf, CRLF);
1078 } 1080 }
@@ -1096,9 +1098,14 @@ check_http (void)
1096 *pos = ' '; 1098 *pos = ' ';
1097 } 1099 }
1098 buffer[i] = '\0'; 1100 buffer[i] = '\0';
1099 xasprintf (&full_page_new, "%s%s", full_page, buffer); 1101
1100 free (full_page); 1102 if ((full_page_new = realloc(full_page, pagesize + i + 1)) == NULL)
1103 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate memory for full_page\n"));
1104
1105 memmove(&full_page_new[pagesize], buffer, i + 1);
1106
1101 full_page = full_page_new; 1107 full_page = full_page_new;
1108
1102 pagesize += i; 1109 pagesize += i;
1103 1110
1104 if (no_body && document_headers_done (full_page)) { 1111 if (no_body && document_headers_done (full_page)) {
@@ -1110,25 +1117,7 @@ check_http (void)
1110 elapsed_time_transfer = (double)microsec_transfer / 1.0e6; 1117 elapsed_time_transfer = (double)microsec_transfer / 1.0e6;
1111 1118
1112 if (i < 0 && errno != ECONNRESET) { 1119 if (i < 0 && errno != ECONNRESET) {
1113#ifdef HAVE_SSL 1120 die(STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
1114 /*
1115 if (use_ssl) {
1116 sslerr=SSL_get_error(ssl, i);
1117 if ( sslerr == SSL_ERROR_SSL ) {
1118 die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
1119 } else {
1120 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
1121 }
1122 }
1123 else {
1124 */
1125#endif
1126 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
1127#ifdef HAVE_SSL
1128 /* XXX
1129 }
1130 */
1131#endif
1132 } 1121 }
1133 1122
1134 /* return a CRITICAL status if we couldn't read any data */ 1123 /* return a CRITICAL status if we couldn't read any data */
@@ -1253,32 +1242,73 @@ check_http (void)
1253 } 1242 }
1254 1243
1255 /* Page and Header content checks go here */ 1244 /* Page and Header content checks go here */
1256 if (strlen (header_expect)) { 1245 if (strlen(header_expect) > 0) {
1257 if (!strstr (header, header_expect)) { 1246 if (strstr(header, header_expect) == NULL) {
1258 strncpy(&output_header_search[0],header_expect,sizeof(output_header_search)); 1247 // We did not find the header, the rest is for building the output and setting the state
1259 if(output_header_search[sizeof(output_header_search)-1]!='\0') { 1248 char output_header_search[30] = "";
1260 bcopy("...",&output_header_search[sizeof(output_header_search)-4],4); 1249
1250 strncpy(&output_header_search[0], header_expect,
1251 sizeof(output_header_search));
1252
1253 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1254 bcopy("...",
1255 &output_header_search[sizeof(output_header_search) - 4],
1256 4);
1261 } 1257 }
1262 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); 1258
1259 xasprintf (&msg,
1260 _("%sheader '%s' not found on '%s://%s:%d%s', "),
1261 msg,
1262 output_header_search, use_ssl ? "https" : "http",
1263 host_name ? host_name : server_address, server_port,
1264 server_url);
1265
1263 result = STATE_CRITICAL; 1266 result = STATE_CRITICAL;
1264 } 1267 }
1265 } 1268 }
1266 1269
1270 // At this point we should test if the content is chunked and unchunk it, so
1271 // it can be searched (and possibly printed)
1272 const char *chunked_header_regex_string = "Transfer-Encoding: *chunked *";
1273 regex_t chunked_header_regex;
1274
1275 if (regcomp(&chunked_header_regex, chunked_header_regex_string, REG_ICASE)) {
1276 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to compile chunked_header_regex regex");
1277 }
1278
1279 regmatch_t chre_pmatch[1]; // We actually do not care about this, since we only want to know IF it was found
1280
1281 if (regexec(&chunked_header_regex, header, 1, chre_pmatch, 0) == 0) {
1282 if (verbose) {
1283 printf("Found chunked content\n");
1284 }
1285 // We actually found the chunked header
1286 char *tmp = unchunk_content(page);
1287 if (tmp == NULL) {
1288 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to unchunk message body");
1289 }
1290 page = tmp;
1291 }
1267 1292
1268 if (strlen (string_expect)) { 1293 if (strlen(string_expect) > 0) {
1269 if (!strstr (page, string_expect)) { 1294 if (!strstr(page, string_expect)) {
1270 strncpy(&output_string_search[0],string_expect,sizeof(output_string_search)); 1295 // We found the string the body, the rest is for building the output
1271 if(output_string_search[sizeof(output_string_search)-1]!='\0') { 1296 char output_string_search[30] = "";
1272 bcopy("...",&output_string_search[sizeof(output_string_search)-4],4); 1297 strncpy(&output_string_search[0], string_expect,
1298 sizeof(output_string_search));
1299 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1300 bcopy("...", &output_string_search[sizeof(output_string_search) - 4],
1301 4);
1273 } 1302 }
1274 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); 1303 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);
1275 result = STATE_CRITICAL; 1304 result = STATE_CRITICAL;
1276 } 1305 }
1277 } 1306 }
1278 1307
1279 if (strlen (regexp)) { 1308 if (strlen(regexp) > 0) {
1280 errcode = regexec (&preg, page, REGS, pmatch, 0); 1309 errcode = regexec(&preg, page, REGS, pmatch, 0);
1281 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) { 1310 if ((errcode == 0 && invert_regex == 0) ||
1311 (errcode == REG_NOMATCH && invert_regex == 1)) {
1282 /* OK - No-op to avoid changing the logic around it */ 1312 /* OK - No-op to avoid changing the logic around it */
1283 result = max_state_alt(STATE_OK, result); 1313 result = max_state_alt(STATE_OK, result);
1284 } 1314 }
@@ -1330,7 +1360,7 @@ check_http (void)
1330 perfd_time (elapsed_time), 1360 perfd_time (elapsed_time),
1331 perfd_size (page_len), 1361 perfd_size (page_len),
1332 perfd_time_connect (elapsed_time_connect), 1362 perfd_time_connect (elapsed_time_connect),
1333 use_ssl == TRUE ? perfd_time_ssl (elapsed_time_ssl) : "", 1363 use_ssl == true ? perfd_time_ssl (elapsed_time_ssl) : "",
1334 perfd_time_headers (elapsed_time_headers), 1364 perfd_time_headers (elapsed_time_headers),
1335 perfd_time_firstbyte (elapsed_time_firstbyte), 1365 perfd_time_firstbyte (elapsed_time_firstbyte),
1336 perfd_time_transfer (elapsed_time_transfer)); 1366 perfd_time_transfer (elapsed_time_transfer));
@@ -1352,7 +1382,88 @@ check_http (void)
1352 return STATE_UNKNOWN; 1382 return STATE_UNKNOWN;
1353} 1383}
1354 1384
1385/* Receivces a pointer to the beginning of the body of a HTTP message
1386 * which is chunked and returns a pointer to a freshly allocated memory
1387 * region containing the unchunked body or NULL if something failed.
1388 * The result must be freed by the caller.
1389 */
1390char *unchunk_content(const char *content) {
1391 // https://en.wikipedia.org/wiki/Chunked_transfer_encoding
1392 // https://www.rfc-editor.org/rfc/rfc7230#section-4.1
1393 char *result = NULL;
1394 size_t content_length = strlen(content);
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 char *result_ptr;
1403
1404 while (true) {
1405 size_of_chunk = strtol(pointer, &endptr, 16);
1406 if (size_of_chunk == LONG_MIN || size_of_chunk == LONG_MAX) {
1407 // Apparently underflow or overflow, should not happen
1408 if (verbose) {
1409 printf("Got an underflow or overflow from strtol at: %u\n", __LINE__);
1410 }
1411 return NULL;
1412 }
1413 if (endptr == pointer) {
1414 // Apparently this was not a number
1415 if (verbose) {
1416 printf("Chunked content did not start with a number at all (Line: %u)\n", __LINE__);
1417 }
1418 return NULL;
1419 }
1420
1421 // So, we got the length of the chunk
1422 if (*endptr == ';') {
1423 // Chunk extension starts here
1424 while (*endptr != '\r') {
1425 endptr++;
1426 }
1427 }
1428
1429 start_of_chunk = endptr + 2;
1430 end_of_chunk = start_of_chunk + size_of_chunk;
1431 length_of_chunk = (long)(end_of_chunk - start_of_chunk);
1432 pointer = end_of_chunk + 2; //Next number should be here
1433
1434 if (length_of_chunk == 0) {
1435 // Chunk length is 0, so this is the last one
1436 break;
1437 }
1355 1438
1439 overall_size += length_of_chunk;
1440
1441 if (result == NULL) {
1442 result = (char *)calloc(length_of_chunk, sizeof(char));
1443 if (result == NULL) {
1444 if (verbose) {
1445 printf("Failed to allocate memory for unchunked body\n");
1446 }
1447 return NULL;
1448 }
1449 result_ptr = result;
1450 } else {
1451 void *tmp = realloc(result, overall_size);
1452 if (tmp == NULL) {
1453 if (verbose) {
1454 printf("Failed to allocate memory for unchunked body\n");
1455 }
1456 return NULL;
1457 }
1458 }
1459
1460 memcpy(result_ptr, start_of_chunk, size_of_chunk);
1461 result_ptr = result_ptr + size_of_chunk;
1462 }
1463
1464 result[overall_size] = '\0';
1465 return result;
1466}
1356 1467
1357/* per RFC 2396 */ 1468/* per RFC 2396 */
1358#define URI_HTTP "%5[HTPShtps]" 1469#define URI_HTTP "%5[HTPShtps]"
@@ -1363,7 +1474,9 @@ check_http (void)
1363#define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH 1474#define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1364#define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT 1475#define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1365#define HD4 URI_HTTP "://" URI_HOST 1476#define HD4 URI_HTTP "://" URI_HOST
1366#define HD5 URI_PATH 1477/* relative reference redirect like //www.site.org/test https://tools.ietf.org/html/rfc3986 */
1478#define HD5 "//" URI_HOST "/" URI_PATH
1479#define HD6 URI_PATH
1367 1480
1368void 1481void
1369redir (char *pos, char *status_line) 1482redir (char *pos, char *status_line)
@@ -1440,9 +1553,21 @@ redir (char *pos, char *status_line)
1440 use_ssl = server_type_check (type); 1553 use_ssl = server_type_check (type);
1441 i = server_port_check (use_ssl); 1554 i = server_port_check (use_ssl);
1442 } 1555 }
1556 /* URI_HTTP, URI_HOST, URI_PATH */
1557 else if (sscanf (pos, HD5, addr, url) == 2) {
1558 if(use_ssl){
1559 strcpy (type,"https");
1560 }
1561 else{
1562 strcpy (type, server_type);
1563 }
1564 xasprintf (&url, "/%s", url);
1565 use_ssl = server_type_check (type);
1566 i = server_port_check (use_ssl);
1567 }
1443 1568
1444 /* URI_PATH */ 1569 /* URI_PATH */
1445 else if (sscanf (pos, HD5, url) == 1) { 1570 else if (sscanf (pos, HD6, url) == 1) {
1446 /* relative url */ 1571 /* relative url */
1447 if ((url[0] != '/')) { 1572 if ((url[0] != '/')) {
1448 if ((x = strrchr(server_url, '/'))) 1573 if ((x = strrchr(server_url, '/')))
@@ -1511,13 +1636,13 @@ redir (char *pos, char *status_line)
1511} 1636}
1512 1637
1513 1638
1514int 1639bool
1515server_type_check (const char *type) 1640server_type_check (const char *type)
1516{ 1641{
1517 if (strcmp (type, "https")) 1642 if (strcmp (type, "https"))
1518 return FALSE; 1643 return false;
1519 else 1644 else
1520 return TRUE; 1645 return true;
1521} 1646}
1522 1647
1523int 1648int
@@ -1532,42 +1657,42 @@ server_port_check (int ssl_flag)
1532char *perfd_time (double elapsed_time) 1657char *perfd_time (double elapsed_time)
1533{ 1658{
1534 return fperfdata ("time", elapsed_time, "s", 1659 return fperfdata ("time", elapsed_time, "s",
1535 thlds->warning?TRUE:FALSE, thlds->warning?thlds->warning->end:0, 1660 thlds->warning?true:false, thlds->warning?thlds->warning->end:0,
1536 thlds->critical?TRUE:FALSE, thlds->critical?thlds->critical->end:0, 1661 thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
1537 TRUE, 0, TRUE, socket_timeout); 1662 true, 0, true, socket_timeout);
1538} 1663}
1539 1664
1540char *perfd_time_connect (double elapsed_time_connect) 1665char *perfd_time_connect (double elapsed_time_connect)
1541{ 1666{
1542 return fperfdata ("time_connect", elapsed_time_connect, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1667 return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1543} 1668}
1544 1669
1545char *perfd_time_ssl (double elapsed_time_ssl) 1670char *perfd_time_ssl (double elapsed_time_ssl)
1546{ 1671{
1547 return fperfdata ("time_ssl", elapsed_time_ssl, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1672 return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1548} 1673}
1549 1674
1550char *perfd_time_headers (double elapsed_time_headers) 1675char *perfd_time_headers (double elapsed_time_headers)
1551{ 1676{
1552 return fperfdata ("time_headers", elapsed_time_headers, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1677 return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1553} 1678}
1554 1679
1555char *perfd_time_firstbyte (double elapsed_time_firstbyte) 1680char *perfd_time_firstbyte (double elapsed_time_firstbyte)
1556{ 1681{
1557 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1682 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1558} 1683}
1559 1684
1560char *perfd_time_transfer (double elapsed_time_transfer) 1685char *perfd_time_transfer (double elapsed_time_transfer)
1561{ 1686{
1562 return fperfdata ("time_transfer", elapsed_time_transfer, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1687 return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1563} 1688}
1564 1689
1565char *perfd_size (int page_len) 1690char *perfd_size (int page_len)
1566{ 1691{
1567 return perfdata ("size", page_len, "B", 1692 return perfdata ("size", page_len, "B",
1568 (min_page_len>0?TRUE:FALSE), min_page_len, 1693 (min_page_len>0?true:false), min_page_len,
1569 (min_page_len>0?TRUE:FALSE), 0, 1694 (min_page_len>0?true:false), 0,
1570 TRUE, 0, FALSE, 0); 1695 true, 0, false, 0);
1571} 1696}
1572 1697
1573void 1698void