summaryrefslogtreecommitdiffstats
path: root/plugins/check_http.c
diff options
context:
space:
mode:
authorKristian Schuster <116557017+KriSchu@users.noreply.github.com>2023-02-19 23:49:18 +0100
committerKristian Schuster <116557017+KriSchu@users.noreply.github.com>2023-02-19 23:49:18 +0100
commita0d42777217296c0a7bdb1e1be8d8f6de1b24dd7 (patch)
tree8effe94c57b2f9796ba36090b07551baa8f1e1cb /plugins/check_http.c
parentca3d59cd6918c9e2739e783b721d4c1122640fd3 (diff)
parentc07206f2ccc2356aa74bc6813a94c2190017d44e (diff)
downloadmonitoring-plugins-a0d4277.tar.gz
Merge remote-tracking branch 'origin/master' into feature_check_disk_add_ignore_missing_option
Diffstat (limited to 'plugins/check_http.c')
-rw-r--r--plugins/check_http.c318
1 files changed, 218 insertions, 100 deletions
diff --git a/plugins/check_http.c b/plugins/check_http.c
index ff39c591..8dda046f 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,95 @@ 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
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;
1355 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 }
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}
1356 1474
1357/* per RFC 2396 */ 1475/* per RFC 2396 */
1358#define URI_HTTP "%5[HTPShtps]" 1476#define URI_HTTP "%5[HTPShtps]"
@@ -1525,13 +1643,13 @@ redir (char *pos, char *status_line)
1525} 1643}
1526 1644
1527 1645
1528int 1646bool
1529server_type_check (const char *type) 1647server_type_check (const char *type)
1530{ 1648{
1531 if (strcmp (type, "https")) 1649 if (strcmp (type, "https"))
1532 return FALSE; 1650 return false;
1533 else 1651 else
1534 return TRUE; 1652 return true;
1535} 1653}
1536 1654
1537int 1655int
@@ -1546,42 +1664,42 @@ server_port_check (int ssl_flag)
1546char *perfd_time (double elapsed_time) 1664char *perfd_time (double elapsed_time)
1547{ 1665{
1548 return fperfdata ("time", elapsed_time, "s", 1666 return fperfdata ("time", elapsed_time, "s",
1549 thlds->warning?TRUE:FALSE, thlds->warning?thlds->warning->end:0, 1667 thlds->warning?true:false, thlds->warning?thlds->warning->end:0,
1550 thlds->critical?TRUE:FALSE, thlds->critical?thlds->critical->end:0, 1668 thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
1551 TRUE, 0, TRUE, socket_timeout); 1669 true, 0, true, socket_timeout);
1552} 1670}
1553 1671
1554char *perfd_time_connect (double elapsed_time_connect) 1672char *perfd_time_connect (double elapsed_time_connect)
1555{ 1673{
1556 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);
1557} 1675}
1558 1676
1559char *perfd_time_ssl (double elapsed_time_ssl) 1677char *perfd_time_ssl (double elapsed_time_ssl)
1560{ 1678{
1561 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);
1562} 1680}
1563 1681
1564char *perfd_time_headers (double elapsed_time_headers) 1682char *perfd_time_headers (double elapsed_time_headers)
1565{ 1683{
1566 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);
1567} 1685}
1568 1686
1569char *perfd_time_firstbyte (double elapsed_time_firstbyte) 1687char *perfd_time_firstbyte (double elapsed_time_firstbyte)
1570{ 1688{
1571 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);
1572} 1690}
1573 1691
1574char *perfd_time_transfer (double elapsed_time_transfer) 1692char *perfd_time_transfer (double elapsed_time_transfer)
1575{ 1693{
1576 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);
1577} 1695}
1578 1696
1579char *perfd_size (int page_len) 1697char *perfd_size (int page_len)
1580{ 1698{
1581 return perfdata ("size", page_len, "B", 1699 return perfdata ("size", page_len, "B",
1582 (min_page_len>0?TRUE:FALSE), min_page_len, 1700 (min_page_len>0?true:false), min_page_len,
1583 (min_page_len>0?TRUE:FALSE), 0, 1701 (min_page_len>0?true:false), 0,
1584 TRUE, 0, FALSE, 0); 1702 true, 0, false, 0);
1585} 1703}
1586 1704
1587void 1705void