summaryrefslogtreecommitdiffstats
path: root/plugins/check_http.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_http.c')
-rw-r--r--plugins/check_http.c3604
1 files changed, 1843 insertions, 1761 deletions
diff --git a/plugins/check_http.c b/plugins/check_http.c
index 97c0e39a..73e4f3b6 100644
--- a/plugins/check_http.c
+++ b/plugins/check_http.c
@@ -1,35 +1,35 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_http plugin 3 * Monitoring check_http plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2024 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_http plugin 10 * This file contains the check_http plugin
11* 11 *
12* This plugin tests the HTTP service on the specified host. It can test 12 * This plugin tests the HTTP service on the specified host. It can test
13* normal (http) and secure (https) servers, follow redirects, search for 13 * normal (http) and secure (https) servers, follow redirects, search for
14* strings and regular expressions, check connection times, and report on 14 * strings and regular expressions, check connection times, and report on
15* certificate expiration times. 15 * certificate expiration times.
16* 16 *
17* 17 *
18* This program is free software: you can redistribute it and/or modify 18 * This program is free software: you can redistribute it and/or modify
19* it under the terms of the GNU General Public License as published by 19 * it under the terms of the GNU General Public License as published by
20* the Free Software Foundation, either version 3 of the License, or 20 * the Free Software Foundation, either version 3 of the License, or
21* (at your option) any later version. 21 * (at your option) any later version.
22* 22 *
23* This program is distributed in the hope that it will be useful, 23 * This program is distributed in the hope that it will be useful,
24* but WITHOUT ANY WARRANTY; without even the implied warranty of 24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26* GNU General Public License for more details. 26 * GNU General Public License for more details.
27* 27 *
28* You should have received a copy of the GNU General Public License 28 * You should have received a copy of the GNU General Public License
29* along with this program. If not, see <http://www.gnu.org/licenses/>. 29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30* 30 *
31* 31 *
32*****************************************************************************/ 32 *****************************************************************************/
33 33
34const char *progname = "check_http"; 34const char *progname = "check_http";
35const char *copyright = "1999-2024"; 35const char *copyright = "1999-2024";
@@ -41,7 +41,6 @@ const char *email = "devel@monitoring-plugins.org";
41#include "base64.h" 41#include "base64.h"
42#include "netutils.h" 42#include "netutils.h"
43#include "utils.h" 43#include "utils.h"
44#include "base64.h"
45#include <ctype.h> 44#include <ctype.h>
46 45
47#define STICKY_NONE 0 46#define STICKY_NONE 0
@@ -50,1346 +49,1407 @@ const char *email = "devel@monitoring-plugins.org";
50 49
51#define HTTP_EXPECT "HTTP/1." 50#define HTTP_EXPECT "HTTP/1."
52enum { 51enum {
53 MAX_IPV4_HOSTLENGTH = 255, 52 MAX_IPV4_HOSTLENGTH = 255,
54 HTTP_PORT = 80, 53 HTTP_PORT = 80,
55 HTTPS_PORT = 443, 54 HTTPS_PORT = 443,
56 MAX_PORT = 65535, 55 MAX_PORT = 65535,
57 DEFAULT_MAX_REDIRS = 15 56 DEFAULT_MAX_REDIRS = 15
58}; 57};
59 58
60#ifdef HAVE_SSL 59#ifdef HAVE_SSL
61bool check_cert = false; 60static bool check_cert = false;
62bool continue_after_check_cert = false; 61static bool continue_after_check_cert = false;
63int ssl_version = 0; 62static int ssl_version = 0;
64int days_till_exp_warn, days_till_exp_crit; 63static int days_till_exp_warn, days_till_exp_crit;
65char *randbuff; 64# define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
66X509 *server_cert; 65# define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
67# define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
68# define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
69#else /* ifndef HAVE_SSL */ 66#else /* ifndef HAVE_SSL */
70# define my_recv(buf, len) read(sd, buf, len) 67# define my_recv(buf, len) read(sd, buf, len)
71# define my_send(buf, len) send(sd, buf, len, 0) 68# define my_send(buf, len) send(sd, buf, len, 0)
72#endif /* HAVE_SSL */ 69#endif /* HAVE_SSL */
73bool no_body = false; 70static bool no_body = false;
74int maximum_age = -1; 71static int maximum_age = -1;
75 72
76enum { 73enum {
77 REGS = 2, 74 REGS = 2,
78 MAX_RE_SIZE = 1024 75 MAX_RE_SIZE = 1024
79}; 76};
80#include "regex.h" 77#include "regex.h"
81regex_t preg; 78static regex_t preg;
82regmatch_t pmatch[REGS]; 79static regmatch_t pmatch[REGS];
83char regexp[MAX_RE_SIZE]; 80static char regexp[MAX_RE_SIZE];
84char errbuf[MAX_INPUT_BUFFER]; 81static char errbuf[MAX_INPUT_BUFFER];
85int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE; 82static int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
86int errcode; 83static int errcode;
87int invert_regex = 0; 84static int invert_regex = 0;
88int state_regex = STATE_CRITICAL; 85static int state_regex = STATE_CRITICAL;
89 86
90struct timeval tv; 87static struct timeval tv;
91struct timeval tv_temp; 88static struct timeval tv_temp;
92 89
93#define HTTP_URL "/" 90#define HTTP_URL "/"
94#define CRLF "\r\n" 91#define CRLF "\r\n"
95 92
96bool specify_port = false; 93static bool specify_port = false;
97int server_port = HTTP_PORT; 94static int server_port = HTTP_PORT;
98int virtual_port = 0; 95static int virtual_port = 0;
99char server_port_text[6] = ""; 96static char server_type[6] = "http";
100char server_type[6] = "http"; 97static char *server_address;
101char *server_address; 98static char *host_name;
102char *host_name; 99static int host_name_length;
103int host_name_length; 100static char *server_url;
104char *server_url; 101static char *user_agent;
105char *user_agent; 102static int server_url_length;
106int server_url_length; 103static int server_expect_yn = 0;
107int server_expect_yn = 0; 104static char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
108char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT; 105static char header_expect[MAX_INPUT_BUFFER] = "";
109char header_expect[MAX_INPUT_BUFFER] = ""; 106static char string_expect[MAX_INPUT_BUFFER] = "";
110char string_expect[MAX_INPUT_BUFFER] = ""; 107static char *warning_thresholds = NULL;
111char *warning_thresholds = NULL; 108static char *critical_thresholds = NULL;
112char *critical_thresholds = NULL; 109static thresholds *thlds;
113thresholds *thlds; 110static char user_auth[MAX_INPUT_BUFFER] = "";
114char user_auth[MAX_INPUT_BUFFER] = ""; 111static char proxy_auth[MAX_INPUT_BUFFER] = "";
115char proxy_auth[MAX_INPUT_BUFFER] = ""; 112static bool display_html = false;
116bool display_html = false; 113static char **http_opt_headers;
117char **http_opt_headers; 114static int http_opt_headers_count = 0;
118int http_opt_headers_count = 0; 115static int onredirect = STATE_OK;
119int onredirect = STATE_OK; 116static int followsticky = STICKY_NONE;
120int followsticky = STICKY_NONE; 117static bool use_ssl = false;
121bool use_ssl = false; 118static bool use_sni = false;
122bool use_sni = false; 119static bool verbose = false;
123bool verbose = false; 120static bool show_extended_perfdata = false;
124bool show_extended_perfdata = false; 121static bool show_body = false;
125bool show_body = false; 122static int sd;
126int sd; 123static int min_page_len = 0;
127int min_page_len = 0; 124static int max_page_len = 0;
128int max_page_len = 0; 125static int redir_depth = 0;
129int redir_depth = 0; 126static int max_depth = DEFAULT_MAX_REDIRS;
130int max_depth = DEFAULT_MAX_REDIRS; 127static char *http_method;
131char *http_method; 128static char *http_method_proxy;
132char *http_method_proxy; 129static char *http_post_data;
133char *http_post_data; 130static char *http_content_type;
134char *http_content_type; 131static char buffer[MAX_INPUT_BUFFER];
135char buffer[MAX_INPUT_BUFFER]; 132static char *client_cert = NULL;
136char *client_cert = NULL; 133static char *client_privkey = NULL;
137char *client_privkey = NULL;
138 134
139// Forward function declarations 135// Forward function declarations
140bool process_arguments (int, char **); 136static bool process_arguments(int /*argc*/, char ** /*argv*/);
141int check_http (void); 137static int check_http(void);
142void redir (char *pos, char *status_line); 138static void redir(char *pos, char *status_line);
143bool server_type_check(const char *type); 139static bool server_type_check(const char *type);
144int server_port_check(int ssl_flag); 140static int server_port_check(int ssl_flag);
145char *perfd_time (double microsec); 141static char *perfd_time(double elapsed_time);
146char *perfd_time_connect (double microsec); 142static char *perfd_time_connect(double elapsed_time_connect);
147char *perfd_time_ssl (double microsec); 143static char *perfd_time_ssl(double elapsed_time_ssl);
148char *perfd_time_firstbyte (double microsec); 144static char *perfd_time_firstbyte(double elapsed_time_firstbyte);
149char *perfd_time_headers (double microsec); 145static char *perfd_time_headers(double elapsed_time_headers);
150char *perfd_time_transfer (double microsec); 146static char *perfd_time_transfer(double elapsed_time_transfer);
151char *perfd_size (int page_len); 147static char *perfd_size(int page_len);
152void print_help (void); 148void print_help(void);
153void print_usage (void); 149void print_usage(void);
154char *unchunk_content(const char *content); 150static char *unchunk_content(const char *content);
155 151
156int 152int main(int argc, char **argv) {
157main (int argc, char **argv) 153 int result = STATE_UNKNOWN;
158{ 154
159 int result = STATE_UNKNOWN; 155 setlocale(LC_ALL, "");
160 156 bindtextdomain(PACKAGE, LOCALEDIR);
161 setlocale (LC_ALL, ""); 157 textdomain(PACKAGE);
162 bindtextdomain (PACKAGE, LOCALEDIR); 158
163 textdomain (PACKAGE); 159 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
164 160 server_url = strdup(HTTP_URL);
165 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */ 161 server_url_length = strlen(server_url);
166 server_url = strdup(HTTP_URL); 162 xasprintf(&user_agent, "User-Agent: check_http/v%s (monitoring-plugins %s)", NP_VERSION,
167 server_url_length = strlen(server_url); 163 VERSION);
168 xasprintf (&user_agent, "User-Agent: check_http/v%s (monitoring-plugins %s)", 164
169 NP_VERSION, VERSION); 165 /* Parse extra opts if any */
170 166 argv = np_extra_opts(&argc, argv, progname);
171 /* Parse extra opts if any */ 167
172 argv=np_extra_opts (&argc, argv, progname); 168 if (!process_arguments(argc, argv)) {
173 169 usage4(_("Could not parse arguments"));
174 if (process_arguments (argc, argv) == false) 170 }
175 usage4 (_("Could not parse arguments")); 171
176 172 if (display_html) {
177 if (display_html == true) 173 printf("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", use_ssl ? "https" : "http",
178 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 174 host_name ? host_name : server_address, server_port, server_url);
179 use_ssl ? "https" : "http", host_name ? host_name : server_address, 175 }
180 server_port, server_url); 176
181 177 /* initialize alarm signal handling, set socket timeout, start timer */
182 /* initialize alarm signal handling, set socket timeout, start timer */ 178 (void)signal(SIGALRM, socket_timeout_alarm_handler);
183 (void) signal (SIGALRM, socket_timeout_alarm_handler); 179 (void)alarm(socket_timeout);
184 (void) alarm (socket_timeout); 180 gettimeofday(&tv, NULL);
185 gettimeofday (&tv, NULL); 181
186 182 result = check_http();
187 result = check_http (); 183 return result;
188 return result;
189} 184}
190 185
191/* check whether a file exists */ 186/* check whether a file exists */
192void 187void test_file(char *path) {
193test_file (char *path) 188 if (access(path, R_OK) == 0) {
194{ 189 return;
195 if (access(path, R_OK) == 0) 190 }
196 return; 191 usage2(_("file does not exist or is not readable"), path);
197 usage2 (_("file does not exist or is not readable"), path);
198} 192}
199 193
200/* 194/*
201 * process command-line arguments 195 * process command-line arguments
202 * returns true on success, false otherwise 196 * returns true on success, false otherwise
203 */ 197 */
204bool process_arguments (int argc, char **argv) 198bool process_arguments(int argc, char **argv) {
205{ 199 int c = 1;
206 int c = 1; 200 char *p;
207 char *p; 201 char *temp;
208 char *temp; 202
209 203 enum {
210 enum { 204 INVERT_REGEX = CHAR_MAX + 1,
211 INVERT_REGEX = CHAR_MAX + 1, 205 SNI_OPTION,
212 SNI_OPTION, 206 MAX_REDIRS_OPTION,
213 MAX_REDIRS_OPTION, 207 CONTINUE_AFTER_CHECK_CERT,
214 CONTINUE_AFTER_CHECK_CERT, 208 STATE_REGEX,
215 STATE_REGEX 209 TIMEOUT_RESULT
216 }; 210 };
217 211
218 int option = 0; 212 int option = 0;
219 static struct option longopts[] = { 213 static struct option longopts[] = {
220 STD_LONG_OPTS, 214 STD_LONG_OPTS,
221 {"link", no_argument, 0, 'L'}, 215 {"link", no_argument, 0, 'L'},
222 {"nohtml", no_argument, 0, 'n'}, 216 {"nohtml", no_argument, 0, 'n'},
223 {"ssl", optional_argument, 0, 'S'}, 217 {"ssl", optional_argument, 0, 'S'},
224 {"sni", no_argument, 0, SNI_OPTION}, 218 {"sni", no_argument, 0, SNI_OPTION},
225 {"post", required_argument, 0, 'P'}, 219 {"post", required_argument, 0, 'P'},
226 {"method", required_argument, 0, 'j'}, 220 {"method", required_argument, 0, 'j'},
227 {"IP-address", required_argument, 0, 'I'}, 221 {"IP-address", required_argument, 0, 'I'},
228 {"url", required_argument, 0, 'u'}, 222 {"url", required_argument, 0, 'u'},
229 {"port", required_argument, 0, 'p'}, 223 {"port", required_argument, 0, 'p'},
230 {"authorization", required_argument, 0, 'a'}, 224 {"authorization", required_argument, 0, 'a'},
231 {"proxy-authorization", required_argument, 0, 'b'}, 225 {"proxy-authorization", required_argument, 0, 'b'},
232 {"header-string", required_argument, 0, 'd'}, 226 {"header-string", required_argument, 0, 'd'},
233 {"string", required_argument, 0, 's'}, 227 {"string", required_argument, 0, 's'},
234 {"expect", required_argument, 0, 'e'}, 228 {"expect", required_argument, 0, 'e'},
235 {"regex", required_argument, 0, 'r'}, 229 {"regex", required_argument, 0, 'r'},
236 {"ereg", required_argument, 0, 'r'}, 230 {"ereg", required_argument, 0, 'r'},
237 {"eregi", required_argument, 0, 'R'}, 231 {"eregi", required_argument, 0, 'R'},
238 {"linespan", no_argument, 0, 'l'}, 232 {"linespan", no_argument, 0, 'l'},
239 {"onredirect", required_argument, 0, 'f'}, 233 {"onredirect", required_argument, 0, 'f'},
240 {"certificate", required_argument, 0, 'C'}, 234 {"certificate", required_argument, 0, 'C'},
241 {"client-cert", required_argument, 0, 'J'}, 235 {"client-cert", required_argument, 0, 'J'},
242 {"private-key", required_argument, 0, 'K'}, 236 {"private-key", required_argument, 0, 'K'},
243 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT}, 237 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
244 {"useragent", required_argument, 0, 'A'}, 238 {"useragent", required_argument, 0, 'A'},
245 {"header", required_argument, 0, 'k'}, 239 {"header", required_argument, 0, 'k'},
246 {"no-body", no_argument, 0, 'N'}, 240 {"no-body", no_argument, 0, 'N'},
247 {"max-age", required_argument, 0, 'M'}, 241 {"max-age", required_argument, 0, 'M'},
248 {"content-type", required_argument, 0, 'T'}, 242 {"content-type", required_argument, 0, 'T'},
249 {"pagesize", required_argument, 0, 'm'}, 243 {"pagesize", required_argument, 0, 'm'},
250 {"invert-regex", no_argument, NULL, INVERT_REGEX}, 244 {"invert-regex", no_argument, NULL, INVERT_REGEX},
251 {"state-regex", required_argument, 0, STATE_REGEX}, 245 {"state-regex", required_argument, 0, STATE_REGEX},
252 {"use-ipv4", no_argument, 0, '4'}, 246 {"use-ipv4", no_argument, 0, '4'},
253 {"use-ipv6", no_argument, 0, '6'}, 247 {"use-ipv6", no_argument, 0, '6'},
254 {"extended-perfdata", no_argument, 0, 'E'}, 248 {"extended-perfdata", no_argument, 0, 'E'},
255 {"show-body", no_argument, 0, 'B'}, 249 {"show-body", no_argument, 0, 'B'},
256 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION}, 250 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
257 {0, 0, 0, 0} 251 {"timeout-result", required_argument, 0, TIMEOUT_RESULT},
258 }; 252 {0, 0, 0, 0}};
259 253
260 if (argc < 2) 254 if (argc < 2) {
261 return false; 255 return false;
262 256 }
263 for (c = 1; c < argc; c++) { 257
264 if (strcmp ("-to", argv[c]) == 0) 258 for (c = 1; c < argc; c++) {
265 strcpy (argv[c], "-t"); 259 if (strcmp("-to", argv[c]) == 0) {
266 if (strcmp ("-hn", argv[c]) == 0) 260 strcpy(argv[c], "-t");
267 strcpy (argv[c], "-H"); 261 }
268 if (strcmp ("-wt", argv[c]) == 0) 262 if (strcmp("-hn", argv[c]) == 0) {
269 strcpy (argv[c], "-w"); 263 strcpy(argv[c], "-H");
270 if (strcmp ("-ct", argv[c]) == 0) 264 }
271 strcpy (argv[c], "-c"); 265 if (strcmp("-wt", argv[c]) == 0) {
272 if (strcmp ("-nohtml", argv[c]) == 0) 266 strcpy(argv[c], "-w");
273 strcpy (argv[c], "-n"); 267 }
274 } 268 if (strcmp("-ct", argv[c]) == 0) {
275 269 strcpy(argv[c], "-c");
276 while (1) { 270 }
277 c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:nlLS::m:M:NEB", longopts, &option); 271 if (strcmp("-nohtml", argv[c]) == 0) {
278 if (c == -1 || c == EOF) 272 strcpy(argv[c], "-n");
279 break; 273 }
280 274 }
281 switch (c) { 275
282 case '?': /* usage */ 276 while (1) {
283 usage5 (); 277 c = getopt_long(argc, argv,
284 break; 278 "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:nlLS::m:M:NEB",
285 case 'h': /* help */ 279 longopts, &option);
286 print_help (); 280 if (c == -1 || c == EOF) {
287 exit (STATE_UNKNOWN); 281 break;
288 break; 282 }
289 case 'V': /* version */ 283
290 print_revision (progname, NP_VERSION); 284 switch (c) {
291 exit (STATE_UNKNOWN); 285 case '?': /* usage */
292 break; 286 usage5();
293 case 't': /* timeout period */ 287 break;
294 if (!is_intnonneg (optarg)) 288 case 'h': /* help */
295 usage2 (_("Timeout interval must be a positive integer"), optarg); 289 print_help();
296 else 290 exit(STATE_UNKNOWN);
297 socket_timeout = atoi (optarg); 291 break;
298 break; 292 case 'V': /* version */
299 case 'c': /* critical time threshold */ 293 print_revision(progname, NP_VERSION);
300 critical_thresholds = optarg; 294 exit(STATE_UNKNOWN);
301 break; 295 break;
302 case 'w': /* warning time threshold */ 296 case 't': /* timeout period */
303 warning_thresholds = optarg; 297 if (!is_intnonneg(optarg)) {
304 break; 298 usage2(_("Timeout interval must be a positive integer"), optarg);
305 case 'A': /* User Agent String */ 299 } else {
306 xasprintf (&user_agent, "User-Agent: %s", optarg); 300 socket_timeout = atoi(optarg);
307 break; 301 }
308 case 'k': /* Additional headers */ 302 break;
309 if (http_opt_headers_count == 0) 303 case TIMEOUT_RESULT:
310 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count)); 304 if (!strcmp(optarg, "0") || !strcasecmp(optarg, "ok")) {
311 else 305 socket_timeout_state = STATE_OK;
312 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count)); 306 } else if (!strcmp(optarg, "1") || !strcasecmp(optarg, "warning")) {
313 http_opt_headers[http_opt_headers_count - 1] = optarg; 307 socket_timeout_state = STATE_WARNING;
314 /* xasprintf (&http_opt_headers, "%s", optarg); */ 308 } else if (!strcmp(optarg, "2") || !strcasecmp(optarg, "critical")) {
315 break; 309 socket_timeout_state = STATE_CRITICAL;
316 case 'L': /* show html link */ 310 } else if (!strcmp(optarg, "3") || !strcasecmp(optarg, "unknown")) {
317 display_html = true; 311 socket_timeout_state = STATE_UNKNOWN;
318 break; 312 } else {
319 case 'n': /* do not show html link */ 313 usage2(_("Invalid timeout-result state option, give either a return code or state "
320 display_html = false; 314 "name in lowercase"),
321 break; 315 optarg);
322 case 'C': /* Check SSL cert validity */ 316 }
317 break;
318 case 'c': /* critical time threshold */
319 critical_thresholds = optarg;
320 break;
321 case 'w': /* warning time threshold */
322 warning_thresholds = optarg;
323 break;
324 case 'A': /* User Agent String */
325 xasprintf(&user_agent, "User-Agent: %s", optarg);
326 break;
327 case 'k': /* Additional headers */
328 if (http_opt_headers_count == 0) {
329 http_opt_headers = malloc(sizeof(char *) * (++http_opt_headers_count));
330 } else {
331 http_opt_headers =
332 realloc(http_opt_headers, sizeof(char *) * (++http_opt_headers_count));
333 }
334 http_opt_headers[http_opt_headers_count - 1] = optarg;
335 /* xasprintf (&http_opt_headers, "%s", optarg); */
336 break;
337 case 'L': /* show html link */
338 display_html = true;
339 break;
340 case 'n': /* do not show html link */
341 display_html = false;
342 break;
343 case 'C': /* Check SSL cert validity */
323#ifdef HAVE_SSL 344#ifdef HAVE_SSL
324 if ((temp=strchr(optarg,','))!=NULL) { 345 if ((temp = strchr(optarg, ',')) != NULL) {
325 *temp='\0'; 346 *temp = '\0';
326 if (!is_intnonneg (optarg)) 347 if (!is_intnonneg(optarg)) {
327 usage2 (_("Invalid certificate expiration period"), optarg); 348 usage2(_("Invalid certificate expiration period"), optarg);
328 days_till_exp_warn = atoi(optarg); 349 }
329 *temp=','; 350 days_till_exp_warn = atoi(optarg);
330 temp++; 351 *temp = ',';
331 if (!is_intnonneg (temp)) 352 temp++;
332 usage2 (_("Invalid certificate expiration period"), temp); 353 if (!is_intnonneg(temp)) {
333 days_till_exp_crit = atoi (temp); 354 usage2(_("Invalid certificate expiration period"), temp);
334 } 355 }
335 else { 356 days_till_exp_crit = atoi(temp);
336 days_till_exp_crit=0; 357 } else {
337 if (!is_intnonneg (optarg)) 358 days_till_exp_crit = 0;
338 usage2 (_("Invalid certificate expiration period"), optarg); 359 if (!is_intnonneg(optarg)) {
339 days_till_exp_warn = atoi (optarg); 360 usage2(_("Invalid certificate expiration period"), optarg);
340 } 361 }
341 check_cert = true; 362 days_till_exp_warn = atoi(optarg);
342 goto enable_ssl; 363 }
364 check_cert = true;
365 goto enable_ssl;
343#endif 366#endif
344 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */ 367 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
345#ifdef HAVE_SSL 368#ifdef HAVE_SSL
346 continue_after_check_cert = true; 369 continue_after_check_cert = true;
347 break; 370 break;
348#endif 371#endif
349 case 'J': /* use client certificate */ 372 case 'J': /* use client certificate */
350#ifdef HAVE_SSL 373#ifdef HAVE_SSL
351 test_file(optarg); 374 test_file(optarg);
352 client_cert = optarg; 375 client_cert = optarg;
353 goto enable_ssl; 376 goto enable_ssl;
354#endif 377#endif
355 case 'K': /* use client private key */ 378 case 'K': /* use client private key */
356#ifdef HAVE_SSL 379#ifdef HAVE_SSL
357 test_file(optarg); 380 test_file(optarg);
358 client_privkey = optarg; 381 client_privkey = optarg;
359 goto enable_ssl; 382 goto enable_ssl;
360#endif 383#endif
361 case 'S': /* use SSL */ 384 case 'S': /* use SSL */
362#ifdef HAVE_SSL 385#ifdef HAVE_SSL
363 enable_ssl: 386 enable_ssl:
364 /* ssl_version initialized to 0 as a default. Only set if it's non-zero. This helps when we include multiple 387 /* ssl_version initialized to 0 as a default. Only set if it's non-zero. This helps
365 parameters, like -S and -C combinations */ 388 when we include multiple parameters, like -S and -C combinations */
366 use_ssl = true; 389 use_ssl = true;
367 if (c=='S' && optarg != NULL) { 390 if (c == 'S' && optarg != NULL) {
368 int got_plus = strchr(optarg, '+') != NULL; 391 int got_plus = strchr(optarg, '+') != NULL;
369 392
370 if (!strncmp (optarg, "1.2", 3)) 393 if (!strncmp(optarg, "1.2", 3)) {
371 ssl_version = got_plus ? MP_TLSv1_2_OR_NEWER : MP_TLSv1_2; 394 ssl_version = got_plus ? MP_TLSv1_2_OR_NEWER : MP_TLSv1_2;
372 else if (!strncmp (optarg, "1.1", 3)) 395 } else if (!strncmp(optarg, "1.1", 3)) {
373 ssl_version = got_plus ? MP_TLSv1_1_OR_NEWER : MP_TLSv1_1; 396 ssl_version = got_plus ? MP_TLSv1_1_OR_NEWER : MP_TLSv1_1;
374 else if (optarg[0] == '1') 397 } else if (optarg[0] == '1') {
375 ssl_version = got_plus ? MP_TLSv1_OR_NEWER : MP_TLSv1; 398 ssl_version = got_plus ? MP_TLSv1_OR_NEWER : MP_TLSv1;
376 else if (optarg[0] == '3') 399 } else if (optarg[0] == '3') {
377 ssl_version = got_plus ? MP_SSLv3_OR_NEWER : MP_SSLv3; 400 ssl_version = got_plus ? MP_SSLv3_OR_NEWER : MP_SSLv3;
378 else if (optarg[0] == '2') 401 } else if (optarg[0] == '2') {
379 ssl_version = got_plus ? MP_SSLv2_OR_NEWER : MP_SSLv2; 402 ssl_version = got_plus ? MP_SSLv2_OR_NEWER : MP_SSLv2;
380 else 403 } else {
381 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with optional '+' suffix)")); 404 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with "
382 } 405 "optional '+' suffix)"));
383 if (specify_port == false) 406 }
384 server_port = HTTPS_PORT; 407 }
408 if (!specify_port) {
409 server_port = HTTPS_PORT;
410 }
385#else 411#else
386 /* -C -J and -K fall through to here without SSL */ 412 /* -C -J and -K fall through to here without SSL */
387 usage4 (_("Invalid option - SSL is not available")); 413 usage4(_("Invalid option - SSL is not available"));
388#endif 414#endif
389 break; 415 break;
390 case SNI_OPTION: 416 case SNI_OPTION:
391 use_sni = true; 417 use_sni = true;
392 break; 418 break;
393 case MAX_REDIRS_OPTION: 419 case MAX_REDIRS_OPTION:
394 if (!is_intnonneg (optarg)) 420 if (!is_intnonneg(optarg)) {
395 usage2 (_("Invalid max_redirs count"), optarg); 421 usage2(_("Invalid max_redirs count"), optarg);
396 else { 422 } else {
397 max_depth = atoi (optarg); 423 max_depth = atoi(optarg);
398 } 424 }
399 break; 425 break;
400 case 'f': /* onredirect */ 426 case 'f': /* onredirect */
401 if (!strcmp (optarg, "stickyport")) 427 if (!strcmp(optarg, "stickyport")) {
402 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT; 428 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST | STICKY_PORT;
403 else if (!strcmp (optarg, "sticky")) 429 } else if (!strcmp(optarg, "sticky")) {
404 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST; 430 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST;
405 else if (!strcmp (optarg, "follow")) 431 } else if (!strcmp(optarg, "follow")) {
406 onredirect = STATE_DEPENDENT, followsticky = STICKY_NONE; 432 onredirect = STATE_DEPENDENT, followsticky = STICKY_NONE;
407 else if (!strcmp (optarg, "unknown")) 433 } else if (!strcmp(optarg, "unknown")) {
408 onredirect = STATE_UNKNOWN; 434 onredirect = STATE_UNKNOWN;
409 else if (!strcmp (optarg, "ok")) 435 } else if (!strcmp(optarg, "ok")) {
410 onredirect = STATE_OK; 436 onredirect = STATE_OK;
411 else if (!strcmp (optarg, "warning")) 437 } else if (!strcmp(optarg, "warning")) {
412 onredirect = STATE_WARNING; 438 onredirect = STATE_WARNING;
413 else if (!strcmp (optarg, "critical")) 439 } else if (!strcmp(optarg, "critical")) {
414 onredirect = STATE_CRITICAL; 440 onredirect = STATE_CRITICAL;
415 else usage2 (_("Invalid onredirect option"), optarg); 441 } else {
416 if (verbose) 442 usage2(_("Invalid onredirect option"), optarg);
417 printf(_("option f:%d \n"), onredirect); 443 }
418 break; 444 if (verbose) {
419 /* Note: H, I, and u must be malloc'd or will fail on redirects */ 445 printf(_("option f:%d \n"), onredirect);
420 case 'H': /* Host Name (virtual host) */ 446 }
421 host_name = strdup (optarg); 447 break;
422 if (host_name[0] == '[') { 448 /* Note: H, I, and u must be malloc'd or will fail on redirects */
423 if ((p = strstr (host_name, "]:")) != NULL) { /* [IPv6]:port */ 449 case 'H': /* Host Name (virtual host) */
424 virtual_port = atoi (p + 2); 450 host_name = strdup(optarg);
425 /* cut off the port */ 451 if (host_name[0] == '[') {
426 host_name_length = strlen (host_name) - strlen (p) - 1; 452 if ((p = strstr(host_name, "]:")) != NULL) { /* [IPv6]:port */
427 free (host_name); 453 virtual_port = atoi(p + 2);
428 host_name = strndup (optarg, host_name_length); 454 /* cut off the port */
429 if (specify_port == false) 455 host_name_length = strlen(host_name) - strlen(p) - 1;
430 server_port = virtual_port; 456 free(host_name);
431 } 457 host_name = strndup(optarg, host_name_length);
432 } else if ((p = strchr (host_name, ':')) != NULL 458 if (!specify_port) {
433 && strchr (++p, ':') == NULL) { /* IPv4:port or host:port */ 459 server_port = virtual_port;
434 virtual_port = atoi (p); 460 }
435 /* cut off the port */ 461 }
436 host_name_length = strlen (host_name) - strlen (p) - 1; 462 } else if ((p = strchr(host_name, ':')) != NULL &&
437 free (host_name); 463 strchr(++p, ':') == NULL) { /* IPv4:port or host:port */
438 host_name = strndup (optarg, host_name_length); 464 virtual_port = atoi(p);
439 if (specify_port == false) 465 /* cut off the port */
440 server_port = virtual_port; 466 host_name_length = strlen(host_name) - strlen(p) - 1;
441 } 467 free(host_name);
442 break; 468 host_name = strndup(optarg, host_name_length);
443 case 'I': /* Server IP-address */ 469 if (!specify_port) {
444 server_address = strdup (optarg); 470 server_port = virtual_port;
445 break; 471 }
446 case 'u': /* URL path */ 472 }
447 server_url = strdup (optarg); 473 break;
448 server_url_length = strlen (server_url); 474 case 'I': /* Server IP-address */
449 break; 475 server_address = strdup(optarg);
450 case 'p': /* Server port */ 476 break;
451 if (!is_intnonneg (optarg)) 477 case 'u': /* URL path */
452 usage2 (_("Invalid port number"), optarg); 478 server_url = strdup(optarg);
453 else { 479 server_url_length = strlen(server_url);
454 server_port = atoi (optarg); 480 break;
455 specify_port = true; 481 case 'p': /* Server port */
456 } 482 if (!is_intnonneg(optarg)) {
457 break; 483 usage2(_("Invalid port number"), optarg);
458 case 'a': /* authorization info */ 484 } else {
459 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1); 485 server_port = atoi(optarg);
460 user_auth[MAX_INPUT_BUFFER - 1] = 0; 486 specify_port = true;
461 break; 487 }
462 case 'b': /* proxy-authorization info */ 488 break;
463 strncpy (proxy_auth, optarg, MAX_INPUT_BUFFER - 1); 489 case 'a': /* authorization info */
464 proxy_auth[MAX_INPUT_BUFFER - 1] = 0; 490 strncpy(user_auth, optarg, MAX_INPUT_BUFFER - 1);
465 break; 491 user_auth[MAX_INPUT_BUFFER - 1] = 0;
466 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */ 492 break;
467 if (! http_post_data) 493 case 'b': /* proxy-authorization info */
468 http_post_data = strdup (optarg); 494 strncpy(proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
469 if (! http_method) 495 proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
470 http_method = strdup("POST"); 496 break;
471 break; 497 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
472 case 'j': /* Set HTTP method */ 498 if (!http_post_data) {
473 if (http_method) 499 http_post_data = strdup(optarg);
474 free(http_method); 500 }
475 http_method = strdup (optarg); 501 if (!http_method) {
476 char *tmp; 502 http_method = strdup("POST");
477 if ((tmp = strstr(http_method, ":")) != NULL) { 503 }
478 tmp[0] = '\0'; // set the ":" in the middle to 0 504 break;
479 http_method_proxy = ++tmp; // this points to the second part 505 case 'j': /* Set HTTP method */
480 } 506 if (http_method) {
481 break; 507 free(http_method);
482 case 'd': /* string or substring */ 508 }
483 strncpy (header_expect, optarg, MAX_INPUT_BUFFER - 1); 509 http_method = strdup(optarg);
484 header_expect[MAX_INPUT_BUFFER - 1] = 0; 510 char *tmp;
485 break; 511 if ((tmp = strstr(http_method, ":")) != NULL) {
486 case 's': /* string or substring */ 512 tmp[0] = '\0'; // set the ":" in the middle to 0
487 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1); 513 http_method_proxy = ++tmp; // this points to the second part
488 string_expect[MAX_INPUT_BUFFER - 1] = 0; 514 }
489 break; 515 break;
490 case 'e': /* string or substring */ 516 case 'd': /* string or substring */
491 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1); 517 strncpy(header_expect, optarg, MAX_INPUT_BUFFER - 1);
492 server_expect[MAX_INPUT_BUFFER - 1] = 0; 518 header_expect[MAX_INPUT_BUFFER - 1] = 0;
493 server_expect_yn = 1; 519 break;
494 break; 520 case 's': /* string or substring */
495 case 'T': /* Content-type */ 521 strncpy(string_expect, optarg, MAX_INPUT_BUFFER - 1);
496 xasprintf (&http_content_type, "%s", optarg); 522 string_expect[MAX_INPUT_BUFFER - 1] = 0;
497 break; 523 break;
498 case 'l': /* linespan */ 524 case 'e': /* string or substring */
499 cflags &= ~REG_NEWLINE; 525 strncpy(server_expect, optarg, MAX_INPUT_BUFFER - 1);
500 break; 526 server_expect[MAX_INPUT_BUFFER - 1] = 0;
501 case 'R': /* regex */ 527 server_expect_yn = 1;
502 cflags |= REG_ICASE; 528 break;
529 case 'T': /* Content-type */
530 xasprintf(&http_content_type, "%s", optarg);
531 break;
532 case 'l': /* linespan */
533 cflags &= ~REG_NEWLINE;
534 break;
535 case 'R': /* regex */
536 cflags |= REG_ICASE;
503 // fall through 537 // fall through
504 case 'r': /* regex */ 538 case 'r': /* regex */
505 strncpy (regexp, optarg, MAX_RE_SIZE - 1); 539 strncpy(regexp, optarg, MAX_RE_SIZE - 1);
506 regexp[MAX_RE_SIZE - 1] = 0; 540 regexp[MAX_RE_SIZE - 1] = 0;
507 errcode = regcomp (&preg, regexp, cflags); 541 errcode = regcomp(&preg, regexp, cflags);
508 if (errcode != 0) { 542 if (errcode != 0) {
509 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 543 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
510 printf (_("Could Not Compile Regular Expression: %s"), errbuf); 544 printf(_("Could Not Compile Regular Expression: %s"), errbuf);
511 return false; 545 return false;
512 } 546 }
513 break; 547 break;
514 case INVERT_REGEX: 548 case INVERT_REGEX:
515 invert_regex = 1; 549 invert_regex = 1;
516 break; 550 break;
517 case STATE_REGEX: 551 case STATE_REGEX:
518 if (!strcmp (optarg, "critical")) 552 if (!strcmp(optarg, "critical")) {
519 state_regex = STATE_CRITICAL; 553 state_regex = STATE_CRITICAL;
520 else if (!strcmp (optarg, "warning")) 554 } else if (!strcmp(optarg, "warning")) {
521 state_regex = STATE_WARNING; 555 state_regex = STATE_WARNING;
522 else usage2 (_("Invalid state-regex option"), optarg); 556 } else {
523 break; 557 usage2(_("Invalid state-regex option"), optarg);
524 case '4': 558 }
525 address_family = AF_INET; 559 break;
526 break; 560 case '4':
527 case '6': 561 address_family = AF_INET;
528#ifdef USE_IPV6 562 break;
529 address_family = AF_INET6; 563 case '6':
530#else 564 address_family = AF_INET6;
531 usage4 (_("IPv6 support not available")); 565 break;
532#endif 566 case 'v': /* verbose */
533 break; 567 verbose = true;
534 case 'v': /* verbose */ 568 break;
535 verbose = true; 569 case 'm': /* min_page_length */
536 break; 570 {
537 case 'm': /* min_page_length */ 571 char *tmp;
538 { 572 if (strchr(optarg, ':') != (char *)NULL) {
539 char *tmp; 573 /* range, so get two values, min:max */
540 if (strchr(optarg, ':') != (char *)NULL) { 574 tmp = strtok(optarg, ":");
541 /* range, so get two values, min:max */ 575 if (tmp == NULL) {
542 tmp = strtok(optarg, ":"); 576 printf("Bad format: try \"-m min:max\"\n");
543 if (tmp == NULL) { 577 exit(STATE_WARNING);
544 printf("Bad format: try \"-m min:max\"\n"); 578 } else {
545 exit (STATE_WARNING); 579 min_page_len = atoi(tmp);
546 } else 580 }
547 min_page_len = atoi(tmp); 581
548 582 tmp = strtok(NULL, ":");
549 tmp = strtok(NULL, ":"); 583 if (tmp == NULL) {
550 if (tmp == NULL) { 584 printf("Bad format: try \"-m min:max\"\n");
551 printf("Bad format: try \"-m min:max\"\n"); 585 exit(STATE_WARNING);
552 exit (STATE_WARNING); 586 } else {
553 } else 587 max_page_len = atoi(tmp);
554 max_page_len = atoi(tmp); 588 }
555 } else 589 } else {
556 min_page_len = atoi (optarg); 590 min_page_len = atoi(optarg);
557 break; 591 }
558 } 592 break;
559 case 'N': /* no-body */ 593 }
560 no_body = true; 594 case 'N': /* no-body */
561 break; 595 no_body = true;
562 case 'M': /* max-age */ 596 break;
563 { 597 case 'M': /* max-age */
564 int L = strlen(optarg); 598 {
565 if (L && optarg[L-1] == 'm') 599 int L = strlen(optarg);
566 maximum_age = atoi (optarg) * 60; 600 if (L && optarg[L - 1] == 'm') {
567 else if (L && optarg[L-1] == 'h') 601 maximum_age = atoi(optarg) * 60;
568 maximum_age = atoi (optarg) * 60 * 60; 602 } else if (L && optarg[L - 1] == 'h') {
569 else if (L && optarg[L-1] == 'd') 603 maximum_age = atoi(optarg) * 60 * 60;
570 maximum_age = atoi (optarg) * 60 * 60 * 24; 604 } else if (L && optarg[L - 1] == 'd') {
571 else if (L && (optarg[L-1] == 's' || 605 maximum_age = atoi(optarg) * 60 * 60 * 24;
572 isdigit (optarg[L-1]))) 606 } else if (L && (optarg[L - 1] == 's' || isdigit(optarg[L - 1]))) {
573 maximum_age = atoi (optarg); 607 maximum_age = atoi(optarg);
574 else { 608 } else {
575 fprintf (stderr, "unparsable max-age: %s\n", optarg); 609 fprintf(stderr, "unparsable max-age: %s\n", optarg);
576 exit (STATE_WARNING); 610 exit(STATE_WARNING);
577 } 611 }
578 } 612 } break;
579 break; 613 case 'E': /* show extended perfdata */
580 case 'E': /* show extended perfdata */ 614 show_extended_perfdata = true;
581 show_extended_perfdata = true; 615 break;
582 break; 616 case 'B': /* print body content after status line */
583 case 'B': /* print body content after status line */ 617 show_body = true;
584 show_body = true; 618 break;
585 break; 619 }
586 } 620 }
587 }
588
589 c = optind;
590
591 if (server_address == NULL && c < argc)
592 server_address = strdup (argv[c++]);
593
594 if (host_name == NULL && c < argc)
595 host_name = strdup (argv[c++]);
596
597 if (server_address == NULL) {
598 if (host_name == NULL)
599 usage4 (_("You must specify a server address or host name"));
600 else
601 server_address = strdup (host_name);
602 }
603
604 set_thresholds(&thlds, warning_thresholds, critical_thresholds);
605
606 if (critical_thresholds && thlds->critical->end>(double)socket_timeout)
607 socket_timeout = (int)thlds->critical->end + 1;
608
609 if (http_method == NULL)
610 http_method = strdup ("GET");
611
612 if (http_method_proxy == NULL)
613 http_method_proxy = strdup ("GET");
614
615 if (client_cert && !client_privkey)
616 usage4 (_("If you use a client certificate you must also specify a private key file"));
617
618 if (virtual_port == 0)
619 virtual_port = server_port;
620
621 return true;
622}
623 621
622 c = optind;
624 623
624 if (server_address == NULL && c < argc) {
625 server_address = strdup(argv[c++]);
626 }
627
628 if (host_name == NULL && c < argc) {
629 host_name = strdup(argv[c++]);
630 }
631
632 if (server_address == NULL) {
633 if (host_name == NULL) {
634 usage4(_("You must specify a server address or host name"));
635 } else {
636 server_address = strdup(host_name);
637 }
638 }
639
640 set_thresholds(&thlds, warning_thresholds, critical_thresholds);
641
642 if (critical_thresholds && thlds->critical->end > (double)socket_timeout) {
643 socket_timeout = (int)thlds->critical->end + 1;
644 }
645
646 if (http_method == NULL) {
647 http_method = strdup("GET");
648 }
649
650 if (http_method_proxy == NULL) {
651 http_method_proxy = strdup("GET");
652 }
653
654 if (client_cert && !client_privkey) {
655 usage4(_("If you use a client certificate you must also specify a private key file"));
656 }
657
658 if (virtual_port == 0) {
659 virtual_port = server_port;
660 }
661
662 return true;
663}
625 664
626/* Returns 1 if we're done processing the document body; 0 to keep going */ 665/* Returns 1 if we're done processing the document body; 0 to keep going */
627static int 666static int document_headers_done(char *full_page) {
628document_headers_done (char *full_page) 667 const char *body;
629{
630 const char *body;
631 668
632 for (body = full_page; *body; body++) { 669 for (body = full_page; *body; body++) {
633 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3)) 670 if (!strncmp(body, "\n\n", 2) || !strncmp(body, "\n\r\n", 3)) {
634 break; 671 break;
635 } 672 }
673 }
636 674
637 if (!*body) 675 if (!*body) {
638 return 0; /* haven't read end of headers yet */ 676 return 0; /* haven't read end of headers yet */
677 }
639 678
640 full_page[body - full_page] = 0; 679 full_page[body - full_page] = 0;
641 return 1; 680 return 1;
642} 681}
643 682
644static time_t 683static time_t parse_time_string(const char *string) {
645parse_time_string (const char *string) 684 struct tm tm;
646{ 685 time_t t;
647 struct tm tm; 686 memset(&tm, 0, sizeof(tm));
648 time_t t; 687
649 memset (&tm, 0, sizeof(tm)); 688 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
650 689
651 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */ 690 if (isupper(string[0]) && /* Tue */
652 691 islower(string[1]) && islower(string[2]) && ',' == string[3] && ' ' == string[4] &&
653 if (isupper (string[0]) && /* Tue */ 692 (isdigit(string[5]) || string[5] == ' ') && /* 25 */
654 islower (string[1]) && 693 isdigit(string[6]) && ' ' == string[7] && isupper(string[8]) && /* Dec */
655 islower (string[2]) && 694 islower(string[9]) && islower(string[10]) && ' ' == string[11] &&
656 ',' == string[3] && 695 isdigit(string[12]) && /* 2001 */
657 ' ' == string[4] && 696 isdigit(string[13]) && isdigit(string[14]) && isdigit(string[15]) && ' ' == string[16] &&
658 (isdigit(string[5]) || string[5] == ' ') && /* 25 */ 697 isdigit(string[17]) && /* 02: */
659 isdigit (string[6]) && 698 isdigit(string[18]) && ':' == string[19] && isdigit(string[20]) && /* 59: */
660 ' ' == string[7] && 699 isdigit(string[21]) && ':' == string[22] && isdigit(string[23]) && /* 03 */
661 isupper (string[8]) && /* Dec */ 700 isdigit(string[24]) && ' ' == string[25] && 'G' == string[26] && /* GMT */
662 islower (string[9]) && 701 'M' == string[27] && /* GMT */
663 islower (string[10]) && 702 'T' == string[28]) {
664 ' ' == string[11] && 703
665 isdigit (string[12]) && /* 2001 */ 704 tm.tm_sec = 10 * (string[23] - '0') + (string[24] - '0');
666 isdigit (string[13]) && 705 tm.tm_min = 10 * (string[20] - '0') + (string[21] - '0');
667 isdigit (string[14]) && 706 tm.tm_hour = 10 * (string[17] - '0') + (string[18] - '0');
668 isdigit (string[15]) && 707 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5] - '0') + (string[6] - '0');
669 ' ' == string[16] && 708 tm.tm_mon = (!strncmp(string + 8, "Jan", 3) ? 0
670 isdigit (string[17]) && /* 02: */ 709 : !strncmp(string + 8, "Feb", 3) ? 1
671 isdigit (string[18]) && 710 : !strncmp(string + 8, "Mar", 3) ? 2
672 ':' == string[19] && 711 : !strncmp(string + 8, "Apr", 3) ? 3
673 isdigit (string[20]) && /* 59: */ 712 : !strncmp(string + 8, "May", 3) ? 4
674 isdigit (string[21]) && 713 : !strncmp(string + 8, "Jun", 3) ? 5
675 ':' == string[22] && 714 : !strncmp(string + 8, "Jul", 3) ? 6
676 isdigit (string[23]) && /* 03 */ 715 : !strncmp(string + 8, "Aug", 3) ? 7
677 isdigit (string[24]) && 716 : !strncmp(string + 8, "Sep", 3) ? 8
678 ' ' == string[25] && 717 : !strncmp(string + 8, "Oct", 3) ? 9
679 'G' == string[26] && /* GMT */ 718 : !strncmp(string + 8, "Nov", 3) ? 10
680 'M' == string[27] && /* GMT */ 719 : !strncmp(string + 8, "Dec", 3) ? 11
681 'T' == string[28]) { 720 : -1);
682 721 tm.tm_year = ((1000 * (string[12] - '0') + 100 * (string[13] - '0') +
683 tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0'); 722 10 * (string[14] - '0') + (string[15] - '0')) -
684 tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0'); 723 1900);
685 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0'); 724
686 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0'); 725 tm.tm_isdst = 0; /* GMT is never in DST, right? */
687 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 : 726
688 !strncmp (string+8, "Feb", 3) ? 1 : 727 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31) {
689 !strncmp (string+8, "Mar", 3) ? 2 : 728 return 0;
690 !strncmp (string+8, "Apr", 3) ? 3 : 729 }
691 !strncmp (string+8, "May", 3) ? 4 : 730
692 !strncmp (string+8, "Jun", 3) ? 5 : 731 /*
693 !strncmp (string+8, "Jul", 3) ? 6 : 732 This is actually wrong: we need to subtract the local timezone
694 !strncmp (string+8, "Aug", 3) ? 7 : 733 offset from GMT from this value. But, that's ok in this usage,
695 !strncmp (string+8, "Sep", 3) ? 8 : 734 because we only comparing these two GMT dates against each other,
696 !strncmp (string+8, "Oct", 3) ? 9 : 735 so it doesn't matter what time zone we parse them in.
697 !strncmp (string+8, "Nov", 3) ? 10 : 736 */
698 !strncmp (string+8, "Dec", 3) ? 11 : 737
699 -1); 738 t = mktime(&tm);
700 tm.tm_year = ((1000 * (string[12]-'0') + 739 if (t == (time_t)-1) {
701 100 * (string[13]-'0') + 740 t = 0;
702 10 * (string[14]-'0') + 741 }
703 (string[15]-'0')) 742
704 - 1900); 743 if (verbose) {
705 744 const char *s = string;
706 tm.tm_isdst = 0; /* GMT is never in DST, right? */ 745 while (*s && *s != '\r' && *s != '\n') {
707 746 fputc(*s++, stdout);
708 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31) 747 }
709 return 0; 748 printf(" ==> %lu\n", (unsigned long)t);
710 749 }
711 /* 750
712 This is actually wrong: we need to subtract the local timezone 751 return t;
713 offset from GMT from this value. But, that's ok in this usage, 752 }
714 because we only comparing these two GMT dates against each other, 753 return 0;
715 so it doesn't matter what time zone we parse them in.
716 */
717
718 t = mktime (&tm);
719 if (t == (time_t) -1) t = 0;
720
721 if (verbose) {
722 const char *s = string;
723 while (*s && *s != '\r' && *s != '\n')
724 fputc (*s++, stdout);
725 printf (" ==> %lu\n", (unsigned long) t);
726 }
727
728 return t;
729
730 } else {
731 return 0;
732 }
733} 754}
734 755
735/* Checks if the server 'reply' is one of the expected 'statuscodes' */ 756/* Checks if the server 'reply' is one of the expected 'statuscodes' */
736static int 757static int expected_statuscode(const char *reply, const char *statuscodes) {
737expected_statuscode (const char *reply, const char *statuscodes) 758 char *expected;
738{ 759 char *code;
739 char *expected, *code; 760 int result = 0;
740 int result = 0; 761
741 762 if ((expected = strdup(statuscodes)) == NULL) {
742 if ((expected = strdup (statuscodes)) == NULL) 763 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
743 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); 764 }
744 765
745 for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ",")) 766 for (code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) {
746 if (strstr (reply, code) != NULL) { 767 if (strstr(reply, code) != NULL) {
747 result = 1; 768 result = 1;
748 break; 769 break;
749 } 770 }
750 771 }
751 free (expected); 772
752 return result; 773 free(expected);
774 return result;
753} 775}
754 776
755static int 777static int check_document_dates(const char *headers, char **msg) {
756check_document_dates (const char *headers, char **msg) 778 const char *s;
757{ 779 char *server_date = 0;
758 const char *s; 780 char *document_date = 0;
759 char *server_date = 0; 781 int date_result = STATE_OK;
760 char *document_date = 0; 782
761 int date_result = STATE_OK; 783 s = headers;
762 784 while (*s) {
763 s = headers; 785 const char *field = s;
764 while (*s) { 786 const char *value = 0;
765 const char *field = s; 787
766 const char *value = 0; 788 /* Find the end of the header field */
767 789 while (*s && !isspace(*s) && *s != ':') {
768 /* Find the end of the header field */ 790 s++;
769 while (*s && !isspace(*s) && *s != ':') 791 }
770 s++; 792
771 793 /* Remember the header value, if any. */
772 /* Remember the header value, if any. */ 794 if (*s == ':') {
773 if (*s == ':') 795 value = ++s;
774 value = ++s; 796 }
775 797
776 /* Skip to the end of the header, including continuation lines. */ 798 /* Skip to the end of the header, including continuation lines. */
777 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) 799 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) {
778 s++; 800 s++;
779 801 }
780 /* Avoid stepping over end-of-string marker */ 802
781 if (*s) 803 /* Avoid stepping over end-of-string marker */
782 s++; 804 if (*s) {
783 805 s++;
784 /* Process this header. */ 806 }
785 if (value && value > field+2) { 807
786 char *ff = (char *) malloc (value-field); 808 /* Process this header. */
787 char *ss = ff; 809 if (value && value > field + 2) {
788 while (field < value-1) 810 char *ff = (char *)malloc(value - field);
789 *ss++ = tolower(*field++); 811 char *ss = ff;
790 *ss++ = 0; 812 while (field < value - 1) {
791 813 *ss++ = tolower(*field++);
792 if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) { 814 }
793 const char *e; 815 *ss++ = 0;
794 while (*value && isspace (*value)) 816
795 value++; 817 if (!strcmp(ff, "date") || !strcmp(ff, "last-modified")) {
796 for (e = value; *e && *e != '\r' && *e != '\n'; e++) 818 const char *e;
797 ; 819 while (*value && isspace(*value)) {
798 ss = (char *) malloc (e - value + 1); 820 value++;
799 strncpy (ss, value, e - value); 821 }
800 ss[e - value] = 0; 822 for (e = value; *e && *e != '\r' && *e != '\n'; e++) {
801 if (!strcmp (ff, "date")) { 823 ;
802 if (server_date) free (server_date); 824 }
803 server_date = ss; 825 ss = (char *)malloc(e - value + 1);
804 } else { 826 strncpy(ss, value, e - value);
805 if (document_date) free (document_date); 827 ss[e - value] = 0;
806 document_date = ss; 828 if (!strcmp(ff, "date")) {
807 } 829 if (server_date) {
808 } 830 free(server_date);
809 free (ff); 831 }
810 } 832 server_date = ss;
811 } 833 } else {
812 834 if (document_date) {
813 /* Done parsing the body. Now check the dates we (hopefully) parsed. */ 835 free(document_date);
814 if (!server_date || !*server_date) { 836 }
815 xasprintf (msg, _("%sServer date unknown, "), *msg); 837 document_date = ss;
816 date_result = max_state_alt(STATE_UNKNOWN, date_result); 838 }
817 } else if (!document_date || !*document_date) { 839 }
818 xasprintf (msg, _("%sDocument modification date unknown, "), *msg); 840 free(ff);
819 date_result = max_state_alt(STATE_CRITICAL, date_result); 841 }
820 } else { 842 }
821 time_t srv_data = parse_time_string (server_date); 843
822 time_t doc_data = parse_time_string (document_date); 844 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
823 845 if (!server_date || !*server_date) {
824 if (srv_data <= 0) { 846 xasprintf(msg, _("%sServer date unknown, "), *msg);
825 xasprintf (msg, _("%sServer date \"%100s\" unparsable, "), *msg, server_date); 847 date_result = max_state_alt(STATE_UNKNOWN, date_result);
826 date_result = max_state_alt(STATE_CRITICAL, date_result); 848 } else if (!document_date || !*document_date) {
827 } else if (doc_data <= 0) { 849 xasprintf(msg, _("%sDocument modification date unknown, "), *msg);
828 xasprintf (msg, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date); 850 date_result = max_state_alt(STATE_CRITICAL, date_result);
829 date_result = max_state_alt(STATE_CRITICAL, date_result); 851 } else {
830 } else if (doc_data > srv_data + 30) { 852 time_t srv_data = parse_time_string(server_date);
831 xasprintf (msg, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data); 853 time_t doc_data = parse_time_string(document_date);
832 date_result = max_state_alt(STATE_CRITICAL, date_result); 854
833 } else if (doc_data < srv_data - maximum_age) { 855 if (srv_data <= 0) {
834 int n = (srv_data - doc_data); 856 xasprintf(msg, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
835 if (n > (60 * 60 * 24 * 2)) { 857 date_result = max_state_alt(STATE_CRITICAL, date_result);
836 xasprintf (msg, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24)); 858 } else if (doc_data <= 0) {
837 date_result = max_state_alt(STATE_CRITICAL, date_result); 859 xasprintf(msg, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
838 } else { 860 date_result = max_state_alt(STATE_CRITICAL, date_result);
839 xasprintf (msg, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60); 861 } else if (doc_data > srv_data + 30) {
840 date_result = max_state_alt(STATE_CRITICAL, date_result); 862 xasprintf(msg, _("%sDocument is %d seconds in the future, "), *msg,
841 } 863 (int)doc_data - (int)srv_data);
842 } 864 date_result = max_state_alt(STATE_CRITICAL, date_result);
843 free (server_date); 865 } else if (doc_data < srv_data - maximum_age) {
844 free (document_date); 866 int n = (srv_data - doc_data);
845 } 867 if (n > (60 * 60 * 24 * 2)) {
846 return date_result; 868 xasprintf(msg, _("%sLast modified %.1f days ago, "), *msg,
869 ((float)n) / (60 * 60 * 24));
870 date_result = max_state_alt(STATE_CRITICAL, date_result);
871 } else {
872 xasprintf(msg, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60),
873 (n / 60) % 60, n % 60);
874 date_result = max_state_alt(STATE_CRITICAL, date_result);
875 }
876 }
877 free(server_date);
878 free(document_date);
879 }
880 return date_result;
847} 881}
848 882
849int 883int get_content_length(const char *headers) {
850get_content_length (const char *headers) 884 const char *s;
851{ 885 int content_length = 0;
852 const char *s; 886
853 int content_length = 0; 887 s = headers;
854 888 while (*s) {
855 s = headers; 889 const char *field = s;
856 while (*s) { 890 const char *value = 0;
857 const char *field = s; 891
858 const char *value = 0; 892 /* Find the end of the header field */
859 893 while (*s && !isspace(*s) && *s != ':') {
860 /* Find the end of the header field */ 894 s++;
861 while (*s && !isspace(*s) && *s != ':') 895 }
862 s++; 896
863 897 /* Remember the header value, if any. */
864 /* Remember the header value, if any. */ 898 if (*s == ':') {
865 if (*s == ':') 899 value = ++s;
866 value = ++s; 900 }
867 901
868 /* Skip to the end of the header, including continuation lines. */ 902 /* Skip to the end of the header, including continuation lines. */
869 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) 903 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) {
870 s++; 904 s++;
871 905 }
872 /* Avoid stepping over end-of-string marker */ 906
873 if (*s) 907 /* Avoid stepping over end-of-string marker */
874 s++; 908 if (*s) {
875 909 s++;
876 /* Process this header. */ 910 }
877 if (value && value > field+2) { 911
878 char *ff = (char *) malloc (value-field); 912 /* Process this header. */
879 char *ss = ff; 913 if (value && value > field + 2) {
880 while (field < value-1) 914 char *ff = (char *)malloc(value - field);
881 *ss++ = tolower(*field++); 915 char *ss = ff;
882 *ss++ = 0; 916 while (field < value - 1) {
883 917 *ss++ = tolower(*field++);
884 if (!strcmp (ff, "content-length")) { 918 }
885 const char *e; 919 *ss++ = 0;
886 while (*value && isspace (*value)) 920
887 value++; 921 if (!strcmp(ff, "content-length")) {
888 for (e = value; *e && *e != '\r' && *e != '\n'; e++) 922 const char *e;
889 ; 923 while (*value && isspace(*value)) {
890 ss = (char *) malloc (e - value + 1); 924 value++;
891 strncpy (ss, value, e - value); 925 }
892 ss[e - value] = 0; 926 for (e = value; *e && *e != '\r' && *e != '\n'; e++) {
893 content_length = atoi(ss); 927 ;
894 free (ss); 928 }
895 } 929 ss = (char *)malloc(e - value + 1);
896 free (ff); 930 strncpy(ss, value, e - value);
897 } 931 ss[e - value] = 0;
898 } 932 content_length = atoi(ss);
899 return (content_length); 933 free(ss);
934 }
935 free(ff);
936 }
937 }
938 return (content_length);
900} 939}
901 940
902char * 941char *prepend_slash(char *path) {
903prepend_slash (char *path) 942 char *newpath;
904{
905 char *newpath;
906 943
907 if (path[0] == '/') 944 if (path[0] == '/') {
908 return path; 945 return path;
946 }
909 947
910 if ((newpath = malloc (strlen(path) + 2)) == NULL) 948 if ((newpath = malloc(strlen(path) + 2)) == NULL) {
911 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); 949 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
912 newpath[0] = '/'; 950 }
913 strcpy (newpath + 1, path); 951 newpath[0] = '/';
914 free (path); 952 strcpy(newpath + 1, path);
915 return newpath; 953 free(path);
954 return newpath;
916} 955}
917 956
918int 957int check_http(void) {
919check_http (void) 958 char *msg;
920{ 959 char *status_line;
921 char *msg; 960 char *status_code;
922 char *status_line; 961 char *header;
923 char *status_code; 962 char *page;
924 char *header; 963 char *auth;
925 char *page; 964 int http_status;
926 char *auth; 965 int i = 0;
927 int http_status; 966 size_t pagesize = 0;
928 int i = 0; 967 char *full_page;
929 size_t pagesize = 0; 968 char *full_page_new;
930 char *full_page; 969 char *buf;
931 char *full_page_new; 970 char *pos;
932 char *buf; 971 long microsec = 0L;
933 char *pos; 972 double elapsed_time = 0.0;
934 long microsec = 0L; 973 long microsec_connect = 0L;
935 double elapsed_time = 0.0; 974 double elapsed_time_connect = 0.0;
936 long microsec_connect = 0L; 975 long microsec_ssl = 0L;
937 double elapsed_time_connect = 0.0; 976 double elapsed_time_ssl = 0.0;
938 long microsec_ssl = 0L; 977 long microsec_firstbyte = 0L;
939 double elapsed_time_ssl = 0.0; 978 double elapsed_time_firstbyte = 0.0;
940 long microsec_firstbyte = 0L; 979 long microsec_headers = 0L;
941 double elapsed_time_firstbyte = 0.0; 980 double elapsed_time_headers = 0.0;
942 long microsec_headers = 0L; 981 long microsec_transfer = 0L;
943 double elapsed_time_headers = 0.0; 982 double elapsed_time_transfer = 0.0;
944 long microsec_transfer = 0L; 983 int page_len = 0;
945 double elapsed_time_transfer = 0.0; 984 int result = STATE_OK;
946 int page_len = 0; 985 char *force_host_header = NULL;
947 int result = STATE_OK; 986
948 char *force_host_header = NULL; 987 /* try to connect to the host at the given port number */
949 988 gettimeofday(&tv_temp, NULL);
950 /* try to connect to the host at the given port number */ 989 if (my_tcp_connect(server_address, server_port, &sd) != STATE_OK) {
951 gettimeofday (&tv_temp, NULL); 990 die(STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
952 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK) 991 }
953 die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n")); 992 microsec_connect = deltime(tv_temp);
954 microsec_connect = deltime (tv_temp); 993
955 994 /* if we are called with the -I option, the -j method is CONNECT and */
956 /* if we are called with the -I option, the -j method is CONNECT and */ 995 /* we received -S for SSL, then we tunnel the request through a proxy*/
957 /* we received -S for SSL, then we tunnel the request through a proxy*/ 996 /* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */
958 /* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */ 997
959 998 if (server_address != NULL && strcmp(http_method, "CONNECT") == 0 && host_name != NULL &&
960 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0 999 use_ssl) {
961 && host_name != NULL && use_ssl == true) { 1000
962 1001 if (verbose) {
963 if (verbose) printf ("Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d\n", server_address, server_port, host_name, HTTPS_PORT); 1002 printf("Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d\n", server_address,
964 asprintf (&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT, user_agent); 1003 server_port, host_name, HTTPS_PORT);
965 if (strlen(proxy_auth)) { 1004 }
966 base64_encode_alloc (proxy_auth, strlen (proxy_auth), &auth); 1005 asprintf(&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT,
967 xasprintf (&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth); 1006 user_agent);
968 } 1007 if (strlen(proxy_auth)) {
969 /* optionally send any other header tag */ 1008 base64_encode_alloc(proxy_auth, strlen(proxy_auth), &auth);
970 if (http_opt_headers_count) { 1009 xasprintf(&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth);
971 for (i = 0; i < http_opt_headers_count ; i++) { 1010 }
972 if (force_host_header != http_opt_headers[i]) { 1011 /* optionally send any other header tag */
973 xasprintf (&buf, "%s%s\r\n", buf, http_opt_headers[i]); 1012 if (http_opt_headers_count) {
974 } 1013 for (i = 0; i < http_opt_headers_count; i++) {
975 } 1014 if (force_host_header != http_opt_headers[i]) {
976 /* This cannot be free'd here because a redirection will then try to access this and segfault */ 1015 xasprintf(&buf, "%s%s\r\n", buf, http_opt_headers[i]);
977 /* Covered in a testcase in tests/check_http.t */ 1016 }
978 /* free(http_opt_headers); */ 1017 }
979 } 1018 /* This cannot be free'd here because a redirection will then try to access this and
980 asprintf (&buf, "%sProxy-Connection: keep-alive\r\n", buf); 1019 * segfault */
981 asprintf (&buf, "%sHost: %s\r\n", buf, host_name); 1020 /* Covered in a testcase in tests/check_http.t */
982 /* we finished our request, send empty line with CRLF */ 1021 /* free(http_opt_headers); */
983 asprintf (&buf, "%s%s", buf, CRLF); 1022 }
984 if (verbose) printf ("%s\n", buf); 1023 asprintf(&buf, "%sProxy-Connection: keep-alive\r\n", buf);
985 send(sd, buf, strlen (buf), 0); 1024 asprintf(&buf, "%sHost: %s\r\n", buf, host_name);
986 buf[0]='\0'; 1025 /* we finished our request, send empty line with CRLF */
987 1026 asprintf(&buf, "%s%s", buf, CRLF);
988 if (verbose) printf ("Receive response from proxy\n"); 1027 if (verbose) {
989 read (sd, buffer, MAX_INPUT_BUFFER-1); 1028 printf("%s\n", buf);
990 if (verbose) printf ("%s", buffer); 1029 }
991 /* Here we should check if we got HTTP/1.1 200 Connection established */ 1030 send(sd, buf, strlen(buf), 0);
992 } 1031 buf[0] = '\0';
1032
1033 if (verbose) {
1034 printf("Receive response from proxy\n");
1035 }
1036 read(sd, buffer, MAX_INPUT_BUFFER - 1);
1037 if (verbose) {
1038 printf("%s", buffer);
1039 }
1040 /* Here we should check if we got HTTP/1.1 200 Connection established */
1041 }
993#ifdef HAVE_SSL 1042#ifdef HAVE_SSL
994 elapsed_time_connect = (double)microsec_connect / 1.0e6; 1043 elapsed_time_connect = (double)microsec_connect / 1.0e6;
995 if (use_ssl == true) { 1044 if (use_ssl) {
996 gettimeofday (&tv_temp, NULL); 1045 gettimeofday(&tv_temp, NULL);
997 result = np_net_ssl_init_with_hostname_version_and_cert(sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey); 1046 result = np_net_ssl_init_with_hostname_version_and_cert(
998 if (verbose) printf ("SSL initialized\n"); 1047 sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey);
999 if (result != STATE_OK) 1048 if (verbose) {
1000 die (STATE_CRITICAL, NULL); 1049 printf("SSL initialized\n");
1001 microsec_ssl = deltime (tv_temp); 1050 }
1002 elapsed_time_ssl = (double)microsec_ssl / 1.0e6; 1051 if (result != STATE_OK) {
1003 if (check_cert == true) { 1052 die(STATE_CRITICAL, _("HTTP CRITICAL - SSL error\n"));
1004 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 1053 }
1005 if (continue_after_check_cert == false) { 1054 microsec_ssl = deltime(tv_temp);
1006 if (sd) close(sd); 1055 elapsed_time_ssl = (double)microsec_ssl / 1.0e6;
1007 np_net_ssl_cleanup(); 1056 if (check_cert) {
1008 return result; 1057 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit);
1009 } 1058 if (!continue_after_check_cert) {
1010 } 1059 if (sd) {
1011 } 1060 close(sd);
1061 }
1062 np_net_ssl_cleanup();
1063 return result;
1064 }
1065 }
1066 }
1012#endif /* HAVE_SSL */ 1067#endif /* HAVE_SSL */
1013 1068
1014 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0 1069 if (server_address != NULL && strcmp(http_method, "CONNECT") == 0 && host_name != NULL &&
1015 && host_name != NULL && use_ssl == true) 1070 use_ssl) {
1016 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); 1071 asprintf(&buf, "%s %s %s\r\n%s\r\n", http_method_proxy, server_url,
1017 else 1072 host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
1018 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent); 1073 } else {
1019 1074 asprintf(&buf, "%s %s %s\r\n%s\r\n", http_method, server_url,
1020 /* tell HTTP/1.1 servers not to keep the connection alive */ 1075 host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
1021 xasprintf (&buf, "%sConnection: close\r\n", buf); 1076 }
1022 1077
1023 /* check if Host header is explicitly set in options */ 1078 /* tell HTTP/1.1 servers not to keep the connection alive */
1024 if (http_opt_headers_count) { 1079 xasprintf(&buf, "%sConnection: close\r\n", buf);
1025 for (i = 0; i < http_opt_headers_count ; i++) { 1080
1026 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) { 1081 /* check if Host header is explicitly set in options */
1027 force_host_header = http_opt_headers[i]; 1082 if (http_opt_headers_count) {
1028 } 1083 for (i = 0; i < http_opt_headers_count; i++) {
1029 } 1084 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) {
1030 } 1085 force_host_header = http_opt_headers[i];
1031 1086 }
1032 /* optionally send the host header info */ 1087 }
1033 if (host_name) { 1088 }
1034 if (force_host_header) { 1089
1035 xasprintf (&buf, "%s%s\r\n", buf, force_host_header); 1090 /* optionally send the host header info */
1036 } 1091 if (host_name) {
1037 else { 1092 if (force_host_header) {
1038 /* 1093 xasprintf(&buf, "%s%s\r\n", buf, force_host_header);
1039 * Specify the port only if we're using a non-default port (see RFC 2616, 1094 } else {
1040 * 14.23). Some server applications/configurations cause trouble if the 1095 /*
1041 * (default) port is explicitly specified in the "Host:" header line. 1096 * Specify the port only if we're using a non-default port (see RFC 2616,
1042 */ 1097 * 14.23). Some server applications/configurations cause trouble if the
1043 if ((use_ssl == false && virtual_port == HTTP_PORT) || 1098 * (default) port is explicitly specified in the "Host:" header line.
1044 (use_ssl == true && virtual_port == HTTPS_PORT) || 1099 */
1045 (server_address != NULL && strcmp(http_method, "CONNECT") == 0 1100 if ((!use_ssl && virtual_port == HTTP_PORT) ||
1046 && host_name != NULL && use_ssl == true)) 1101 (use_ssl && virtual_port == HTTPS_PORT) ||
1047 xasprintf (&buf, "%sHost: %s\r\n", buf, host_name); 1102 (server_address != NULL && strcmp(http_method, "CONNECT") == 0 &&
1048 else 1103 host_name != NULL && use_ssl)) {
1049 xasprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, virtual_port); 1104 xasprintf(&buf, "%sHost: %s\r\n", buf, host_name);
1050 } 1105 } else {
1051 } 1106 xasprintf(&buf, "%sHost: %s:%d\r\n", buf, host_name, virtual_port);
1052 1107 }
1053 /* optionally send any other header tag */ 1108 }
1054 if (http_opt_headers_count) { 1109 }
1055 for (i = 0; i < http_opt_headers_count ; i++) { 1110
1056 if (force_host_header != http_opt_headers[i]) { 1111 /* optionally send any other header tag */
1057 xasprintf (&buf, "%s%s\r\n", buf, http_opt_headers[i]); 1112 if (http_opt_headers_count) {
1058 } 1113 for (i = 0; i < http_opt_headers_count; i++) {
1059 } 1114 if (force_host_header != http_opt_headers[i]) {
1060 /* This cannot be free'd here because a redirection will then try to access this and segfault */ 1115 xasprintf(&buf, "%s%s\r\n", buf, http_opt_headers[i]);
1061 /* Covered in a testcase in tests/check_http.t */ 1116 }
1062 /* free(http_opt_headers); */ 1117 }
1063 } 1118 /* This cannot be free'd here because a redirection will then try to access this and
1064 1119 * segfault */
1065 /* optionally send the authentication info */ 1120 /* Covered in a testcase in tests/check_http.t */
1066 if (strlen(user_auth)) { 1121 /* free(http_opt_headers); */
1067 base64_encode_alloc (user_auth, strlen (user_auth), &auth); 1122 }
1068 xasprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth); 1123
1069 } 1124 /* optionally send the authentication info */
1070 1125 if (strlen(user_auth)) {
1071 /* optionally send the proxy authentication info */ 1126 base64_encode_alloc(user_auth, strlen(user_auth), &auth);
1072 if (strlen(proxy_auth)) { 1127 xasprintf(&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
1073 base64_encode_alloc (proxy_auth, strlen (proxy_auth), &auth); 1128 }
1074 xasprintf (&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth); 1129
1075 } 1130 /* optionally send the proxy authentication info */
1076 1131 if (strlen(proxy_auth)) {
1077 /* either send http POST data (any data, not only POST)*/ 1132 base64_encode_alloc(proxy_auth, strlen(proxy_auth), &auth);
1078 if (http_post_data) { 1133 xasprintf(&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth);
1079 if (http_content_type) { 1134 }
1080 xasprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type); 1135
1081 } else { 1136 /* either send http POST data (any data, not only POST)*/
1082 xasprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf); 1137 if (http_post_data) {
1083 } 1138 if (http_content_type) {
1084 1139 xasprintf(&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
1085 xasprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data)); 1140 } else {
1086 xasprintf (&buf, "%s%s", buf, http_post_data); 1141 xasprintf(&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
1087 } else { 1142 }
1088 /* or just a newline so the server knows we're done with the request */ 1143
1089 xasprintf (&buf, "%s%s", buf, CRLF); 1144 xasprintf(&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen(http_post_data));
1090 } 1145 xasprintf(&buf, "%s%s", buf, http_post_data);
1091 1146 } else {
1092 if (verbose) printf ("%s\n", buf); 1147 /* or just a newline so the server knows we're done with the request */
1093 gettimeofday (&tv_temp, NULL); 1148 xasprintf(&buf, "%s%s", buf, CRLF);
1094 my_send (buf, strlen (buf)); 1149 }
1095 microsec_headers = deltime (tv_temp); 1150
1096 elapsed_time_headers = (double)microsec_headers / 1.0e6; 1151 if (verbose) {
1097 1152 printf("%s\n", buf);
1098 /* fetch the page */ 1153 }
1099 full_page = strdup(""); 1154 gettimeofday(&tv_temp, NULL);
1100 gettimeofday (&tv_temp, NULL); 1155 my_send(buf, strlen(buf));
1101 while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) { 1156 microsec_headers = deltime(tv_temp);
1102 if ((i >= 1) && (elapsed_time_firstbyte <= 0.000001)) { 1157 elapsed_time_headers = (double)microsec_headers / 1.0e6;
1103 microsec_firstbyte = deltime (tv_temp); 1158
1104 elapsed_time_firstbyte = (double)microsec_firstbyte / 1.0e6; 1159 /* fetch the page */
1105 } 1160 full_page = strdup("");
1106 while ((pos = memchr(buffer, '\0', i))) { 1161 gettimeofday(&tv_temp, NULL);
1107 /* replace nul character with a blank */ 1162 while ((i = my_recv(buffer, MAX_INPUT_BUFFER - 1)) > 0) {
1108 *pos = ' '; 1163 if ((i >= 1) && (elapsed_time_firstbyte <= 0.000001)) {
1109 } 1164 microsec_firstbyte = deltime(tv_temp);
1110 buffer[i] = '\0'; 1165 elapsed_time_firstbyte = (double)microsec_firstbyte / 1.0e6;
1111 1166 }
1112 if ((full_page_new = realloc(full_page, pagesize + i + 1)) == NULL) 1167 while ((pos = memchr(buffer, '\0', i))) {
1113 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate memory for full_page\n")); 1168 /* replace nul character with a blank */
1114 1169 *pos = ' ';
1115 memmove(&full_page_new[pagesize], buffer, i + 1); 1170 }
1116 1171 buffer[i] = '\0';
1117 full_page = full_page_new; 1172
1118 1173 if ((full_page_new = realloc(full_page, pagesize + i + 1)) == NULL) {
1119 pagesize += i; 1174 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate memory for full_page\n"));
1120 1175 }
1121 if (no_body && document_headers_done (full_page)) { 1176
1122 i = 0; 1177 memmove(&full_page_new[pagesize], buffer, i + 1);
1123 break; 1178
1124 } 1179 full_page = full_page_new;
1125 } 1180
1126 microsec_transfer = deltime (tv_temp); 1181 pagesize += i;
1127 elapsed_time_transfer = (double)microsec_transfer / 1.0e6; 1182
1128 1183 if (no_body && document_headers_done(full_page)) {
1129 if (i < 0 && errno != ECONNRESET) { 1184 i = 0;
1130 die(STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n")); 1185 break;
1131 } 1186 }
1132 1187 }
1133 /* return a CRITICAL status if we couldn't read any data */ 1188 microsec_transfer = deltime(tv_temp);
1134 if (pagesize == (size_t) 0) 1189 elapsed_time_transfer = (double)microsec_transfer / 1.0e6;
1135 die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n")); 1190
1136 1191 if (i < 0 && errno != ECONNRESET) {
1137 /* close the connection */ 1192 die(STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
1138 if (sd) close(sd); 1193 }
1194
1195 /* return a CRITICAL status if we couldn't read any data */
1196 if (pagesize == (size_t)0) {
1197 die(STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
1198 }
1199
1200 /* close the connection */
1201 if (sd) {
1202 close(sd);
1203 }
1139#ifdef HAVE_SSL 1204#ifdef HAVE_SSL
1140 np_net_ssl_cleanup(); 1205 np_net_ssl_cleanup();
1141#endif 1206#endif
1142 1207
1143 /* Save check time */ 1208 /* Save check time */
1144 microsec = deltime (tv); 1209 microsec = deltime(tv);
1145 elapsed_time = (double)microsec / 1.0e6; 1210 elapsed_time = (double)microsec / 1.0e6;
1146 1211
1147 /* leave full_page untouched so we can free it later */ 1212 /* leave full_page untouched so we can free it later */
1148 page = full_page; 1213 page = full_page;
1149 1214
1150 if (verbose) 1215 if (verbose) {
1151 printf ("%s://%s:%d%s is %d characters\n", 1216 printf("%s://%s:%d%s is %d characters\n", use_ssl ? "https" : "http", server_address,
1152 use_ssl ? "https" : "http", server_address, 1217 server_port, server_url, (int)pagesize);
1153 server_port, server_url, (int)pagesize); 1218 }
1154 1219
1155 /* find status line and null-terminate it */ 1220 /* find status line and null-terminate it */
1156 status_line = page; 1221 status_line = page;
1157 page += (size_t) strcspn (page, "\r\n"); 1222 page += (size_t)strcspn(page, "\r\n");
1158 pos = page; 1223 pos = page;
1159 page += (size_t) strspn (page, "\r\n"); 1224 page += (size_t)strspn(page, "\r\n");
1160 status_line[strcspn(status_line, "\r\n")] = 0; 1225 status_line[strcspn(status_line, "\r\n")] = 0;
1161 strip (status_line); 1226 strip(status_line);
1162 if (verbose) 1227 if (verbose) {
1163 printf ("STATUS: %s\n", status_line); 1228 printf("STATUS: %s\n", status_line);
1164 1229 }
1165 /* find header info and null-terminate it */ 1230
1166 header = page; 1231 /* find header info and null-terminate it */
1167 while (strcspn (page, "\r\n") > 0) { 1232 header = page;
1168 page += (size_t) strcspn (page, "\r\n"); 1233 while (strcspn(page, "\r\n") > 0) {
1169 pos = page; 1234 page += (size_t)strcspn(page, "\r\n");
1170 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) || 1235 pos = page;
1171 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2)) 1236 if ((strspn(page, "\r") == 1 && strspn(page, "\r\n") >= 2) ||
1172 page += (size_t) 2; 1237 (strspn(page, "\n") == 1 && strspn(page, "\r\n") >= 2)) {
1173 else 1238 page += (size_t)2;
1174 page += (size_t) 1; 1239 } else {
1175 } 1240 page += (size_t)1;
1176 page += (size_t) strspn (page, "\r\n"); 1241 }
1177 header[pos - header] = 0; 1242 }
1178 if (verbose) 1243 page += (size_t)strspn(page, "\r\n");
1179 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header, 1244 header[pos - header] = 0;
1180 (no_body ? " [[ skipped ]]" : page)); 1245 if (verbose) {
1181 1246 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
1182 /* make sure the status line matches the response we are looking for */ 1247 (no_body ? " [[ skipped ]]" : page));
1183 if (!expected_statuscode (status_line, server_expect)) { 1248 }
1184 if (server_port == HTTP_PORT) 1249
1185 xasprintf (&msg, 1250 /* make sure the status line matches the response we are looking for */
1186 _("Invalid HTTP response received from host: %s\n"), 1251 if (!expected_statuscode(status_line, server_expect)) {
1187 status_line); 1252 if (server_port == HTTP_PORT) {
1188 else 1253 xasprintf(&msg, _("Invalid HTTP response received from host: %s\n"), status_line);
1189 xasprintf (&msg, 1254 } else {
1190 _("Invalid HTTP response received from host on port %d: %s\n"), 1255 xasprintf(&msg, _("Invalid HTTP response received from host on port %d: %s\n"),
1191 server_port, status_line); 1256 server_port, status_line);
1192 if (show_body) 1257 }
1193 xasprintf (&msg, _("%s\n%s"), msg, page); 1258 if (show_body) {
1194 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg); 1259 xasprintf(&msg, _("%s\n%s"), msg, page);
1195 } 1260 }
1196 1261 die(STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
1197 /* Bypass normal status line check if server_expect was set by user and not default */ 1262 }
1198 /* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */ 1263
1199 if ( server_expect_yn ) { 1264 /* Bypass normal status line check if server_expect was set by user and not default */
1200 xasprintf (&msg, 1265 /* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */
1201 _("Status line output matched \"%s\" - "), server_expect); 1266 if (server_expect_yn) {
1202 if (verbose) 1267 xasprintf(&msg, _("Status line output matched \"%s\" - "), server_expect);
1203 printf ("%s\n",msg); 1268 if (verbose) {
1204 } 1269 printf("%s\n", msg);
1205 else { 1270 }
1206 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */ 1271 } else {
1207 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */ 1272 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
1208 /* Status-Code = 3 DIGITS */ 1273 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
1209 1274 /* Status-Code = 3 DIGITS */
1210 status_code = strchr (status_line, ' ') + sizeof (char); 1275
1211 if (strspn (status_code, "1234567890") != 3) 1276 status_code = strchr(status_line, ' ') + sizeof(char);
1212 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line); 1277 if (strspn(status_code, "1234567890") != 3) {
1213 1278 die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
1214 http_status = atoi (status_code); 1279 }
1215 1280
1216 /* check the return code */ 1281 http_status = atoi(status_code);
1217 1282
1218 if (http_status >= 600 || http_status < 100) { 1283 /* check the return code */
1219 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line); 1284
1220 } 1285 if (http_status >= 600 || http_status < 100) {
1221 /* server errors result in a critical state */ 1286 die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
1222 else if (http_status >= 500) { 1287 }
1223 xasprintf (&msg, _("%s - "), status_line); 1288 /* server errors result in a critical state */
1224 result = STATE_CRITICAL; 1289 else if (http_status >= 500) {
1225 } 1290 xasprintf(&msg, _("%s - "), status_line);
1226 /* client errors result in a warning state */ 1291 result = STATE_CRITICAL;
1227 else if (http_status >= 400) { 1292 }
1228 xasprintf (&msg, _("%s - "), status_line); 1293 /* client errors result in a warning state */
1229 result = max_state_alt(STATE_WARNING, result); 1294 else if (http_status >= 400) {
1230 } 1295 xasprintf(&msg, _("%s - "), status_line);
1231 /* check redirected page if specified */ 1296 result = max_state_alt(STATE_WARNING, result);
1232 else if (http_status >= 300) { 1297 }
1233 1298 /* check redirected page if specified */
1234 if (onredirect == STATE_DEPENDENT) 1299 else if (http_status >= 300) {
1235 redir (header, status_line); 1300
1236 else 1301 if (onredirect == STATE_DEPENDENT) {
1237 result = max_state_alt(onredirect, result); 1302 redir(header, status_line);
1238 xasprintf (&msg, _("%s - "), status_line); 1303 } else {
1239 } /* end if (http_status >= 300) */ 1304 result = max_state_alt(onredirect, result);
1240 else { 1305 }
1241 /* Print OK status anyway */ 1306 xasprintf(&msg, _("%s - "), status_line);
1242 xasprintf (&msg, _("%s - "), status_line); 1307 } /* end if (http_status >= 300) */
1243 } 1308 else {
1244 1309 /* Print OK status anyway */
1245 } /* end else (server_expect_yn) */ 1310 xasprintf(&msg, _("%s - "), status_line);
1246 1311 }
1247 /* reset the alarm - must be called *after* redir or we'll never die on redirects! */ 1312
1248 alarm (0); 1313 } /* end else (server_expect_yn) */
1249 1314
1250 if (maximum_age >= 0) { 1315 /* reset the alarm - must be called *after* redir or we'll never die on redirects! */
1251 result = max_state_alt(check_document_dates(header, &msg), result); 1316 alarm(0);
1252 } 1317
1253 1318 if (maximum_age >= 0) {
1254 /* Page and Header content checks go here */ 1319 result = max_state_alt(check_document_dates(header, &msg), result);
1255 if (strlen(header_expect) > 0) { 1320 }
1256 if (strstr(header, header_expect) == NULL) { 1321
1257 // We did not find the header, the rest is for building the output and setting the state 1322 /* Page and Header content checks go here */
1258 char output_header_search[30] = ""; 1323 if (strlen(header_expect) > 0) {
1259 1324 if (strstr(header, header_expect) == NULL) {
1260 strncpy(&output_header_search[0], header_expect, 1325 // We did not find the header, the rest is for building the output and setting the state
1261 sizeof(output_header_search)); 1326 char output_header_search[30] = "";
1262 1327
1263 if (output_header_search[sizeof(output_header_search) - 1] != '\0') { 1328 strncpy(&output_header_search[0], header_expect, sizeof(output_header_search));
1264 bcopy("...", 1329
1265 &output_header_search[sizeof(output_header_search) - 4], 1330 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1266 4); 1331 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4);
1267 } 1332 }
1268 1333
1269 xasprintf (&msg, 1334 xasprintf(&msg, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg,
1270 _("%sheader '%s' not found on '%s://%s:%d%s', "), 1335 output_header_search, use_ssl ? "https" : "http",
1271 msg, 1336 host_name ? host_name : server_address, server_port, server_url);
1272 output_header_search, use_ssl ? "https" : "http", 1337
1273 host_name ? host_name : server_address, server_port, 1338 result = STATE_CRITICAL;
1274 server_url); 1339 }
1275 1340 }
1276 result = STATE_CRITICAL; 1341
1277 } 1342 // At this point we should test if the content is chunked and unchunk it, so
1278 } 1343 // it can be searched (and possibly printed)
1279 1344 const char *chunked_header_regex_string = "Transfer-Encoding: *chunked *";
1280 // At this point we should test if the content is chunked and unchunk it, so 1345 regex_t chunked_header_regex;
1281 // it can be searched (and possibly printed) 1346
1282 const char *chunked_header_regex_string = "Transfer-Encoding: *chunked *"; 1347 if (regcomp(&chunked_header_regex, chunked_header_regex_string, REG_ICASE)) {
1283 regex_t chunked_header_regex; 1348 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN),
1284 1349 "Failed to compile chunked_header_regex regex");
1285 if (regcomp(&chunked_header_regex, chunked_header_regex_string, REG_ICASE)) { 1350 }
1286 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to compile chunked_header_regex regex"); 1351
1287 } 1352 regmatch_t chre_pmatch[1]; // We actually do not care about this, since we only want to know IF
1288 1353 // it was found
1289 regmatch_t chre_pmatch[1]; // We actually do not care about this, since we only want to know IF it was found 1354
1290 1355 if (!no_body && regexec(&chunked_header_regex, header, 1, chre_pmatch, 0) == 0) {
1291 if (!no_body && regexec(&chunked_header_regex, header, 1, chre_pmatch, 0) == 0) { 1356 if (verbose) {
1292 if (verbose) { 1357 printf("Found chunked content\n");
1293 printf("Found chunked content\n"); 1358 }
1294 } 1359 // We actually found the chunked header
1295 // We actually found the chunked header 1360 char *tmp = unchunk_content(page);
1296 char *tmp = unchunk_content(page); 1361 if (tmp == NULL) {
1297 if (tmp == NULL) { 1362 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN),
1298 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to unchunk message body"); 1363 "Failed to unchunk message body");
1299 } 1364 }
1300 page = tmp; 1365 page = tmp;
1301 } 1366 }
1302 1367
1303 if (strlen(string_expect) > 0) { 1368 if (strlen(string_expect) > 0) {
1304 if (!strstr(page, string_expect)) { 1369 if (!strstr(page, string_expect)) {
1305 // We found the string the body, the rest is for building the output 1370 // We found the string the body, the rest is for building the output
1306 char output_string_search[30] = ""; 1371 char output_string_search[30] = "";
1307 strncpy(&output_string_search[0], string_expect, 1372 strncpy(&output_string_search[0], string_expect, sizeof(output_string_search));
1308 sizeof(output_string_search)); 1373 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1309 if (output_string_search[sizeof(output_string_search) - 1] != '\0') { 1374 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4);
1310 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 1375 }
1311 4); 1376 xasprintf(&msg, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg,
1312 } 1377 output_string_search, use_ssl ? "https" : "http",
1313 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); 1378 host_name ? host_name : server_address, server_port, server_url);
1314 result = STATE_CRITICAL; 1379 result = STATE_CRITICAL;
1315 } 1380 }
1316 } 1381 }
1317 1382
1318 if (strlen(regexp) > 0) { 1383 if (strlen(regexp) > 0) {
1319 errcode = regexec(&preg, page, REGS, pmatch, 0); 1384 errcode = regexec(&preg, page, REGS, pmatch, 0);
1320 if ((errcode == 0 && invert_regex == 0) || 1385 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
1321 (errcode == REG_NOMATCH && invert_regex == 1)) { 1386 /* OK - No-op to avoid changing the logic around it */
1322 /* OK - No-op to avoid changing the logic around it */ 1387 result = max_state_alt(STATE_OK, result);
1323 result = max_state_alt(STATE_OK, result); 1388 } else if ((errcode == REG_NOMATCH && invert_regex == 0) ||
1324 } 1389 (errcode == 0 && invert_regex == 1)) {
1325 else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) { 1390 if (invert_regex == 0) {
1326 if (invert_regex == 0) 1391 xasprintf(&msg, _("%spattern not found, "), msg);
1327 xasprintf (&msg, _("%spattern not found, "), msg); 1392 } else {
1328 else 1393 xasprintf(&msg, _("%spattern found, "), msg);
1329 xasprintf (&msg, _("%spattern found, "), msg); 1394 }
1330 result = state_regex; 1395 result = state_regex;
1331 } 1396 } else {
1332 else { 1397 /* FIXME: Shouldn't that be UNKNOWN? */
1333 /* FIXME: Shouldn't that be UNKNOWN? */ 1398 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1334 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1399 xasprintf(&msg, _("%sExecute Error: %s, "), msg, errbuf);
1335 xasprintf (&msg, _("%sExecute Error: %s, "), msg, errbuf); 1400 result = STATE_CRITICAL;
1336 result = STATE_CRITICAL; 1401 }
1337 } 1402 }
1338 } 1403
1339 1404 /* make sure the page is of an appropriate size */
1340 /* make sure the page is of an appropriate size */ 1405 /* page_len = get_content_length(header); */
1341 /* page_len = get_content_length(header); */ 1406 /* FIXME: Will this work with -N ? IMHO we should use
1342 /* FIXME: Will this work with -N ? IMHO we should use 1407 * get_content_length(header) and always check if it's different than the
1343 * get_content_length(header) and always check if it's different than the 1408 * returned pagesize
1344 * returned pagesize 1409 */
1345 */ 1410 /* FIXME: IIRC pagesize returns headers - shouldn't we make
1346 /* FIXME: IIRC pagesize returns headers - shouldn't we make 1411 * it == get_content_length(header) ??
1347 * it == get_content_length(header) ?? 1412 */
1348 */ 1413 page_len = pagesize;
1349 page_len = pagesize; 1414 if ((max_page_len > 0) && (page_len > max_page_len)) {
1350 if ((max_page_len > 0) && (page_len > max_page_len)) { 1415 xasprintf(&msg, _("%spage size %d too large, "), msg, page_len);
1351 xasprintf (&msg, _("%spage size %d too large, "), msg, page_len); 1416 result = max_state_alt(STATE_WARNING, result);
1352 result = max_state_alt(STATE_WARNING, result); 1417 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1353 } else if ((min_page_len > 0) && (page_len < min_page_len)) { 1418 xasprintf(&msg, _("%spage size %d too small, "), msg, page_len);
1354 xasprintf (&msg, _("%spage size %d too small, "), msg, page_len); 1419 result = max_state_alt(STATE_WARNING, result);
1355 result = max_state_alt(STATE_WARNING, result); 1420 }
1356 } 1421
1357 1422 /* Cut-off trailing characters */
1358 /* Cut-off trailing characters */ 1423 if (msg[strlen(msg) - 2] == ',') {
1359 if(msg[strlen(msg)-2] == ',') 1424 msg[strlen(msg) - 2] = '\0';
1360 msg[strlen(msg)-2] = '\0'; 1425 } else {
1361 else 1426 msg[strlen(msg) - 3] = '\0';
1362 msg[strlen(msg)-3] = '\0'; 1427 }
1363 1428
1364 /* check elapsed time */ 1429 /* check elapsed time */
1365 if (show_extended_perfdata) 1430 if (show_extended_perfdata) {
1366 xasprintf (&msg, 1431 xasprintf(
1367 _("%s - %d bytes in %.3f second response time %s|%s %s %s %s %s %s %s"), 1432 &msg, _("%s - %d bytes in %.3f second response time %s|%s %s %s %s %s %s %s"), msg,
1368 msg, page_len, elapsed_time, 1433 page_len, elapsed_time, (display_html ? "</A>" : ""), perfd_time(elapsed_time),
1369 (display_html ? "</A>" : ""), 1434 perfd_size(page_len), perfd_time_connect(elapsed_time_connect),
1370 perfd_time (elapsed_time), 1435 use_ssl ? perfd_time_ssl(elapsed_time_ssl) : "",
1371 perfd_size (page_len), 1436 perfd_time_headers(elapsed_time_headers), perfd_time_firstbyte(elapsed_time_firstbyte),
1372 perfd_time_connect (elapsed_time_connect), 1437 perfd_time_transfer(elapsed_time_transfer));
1373 use_ssl == true ? perfd_time_ssl (elapsed_time_ssl) : "", 1438 } else {
1374 perfd_time_headers (elapsed_time_headers), 1439 xasprintf(&msg, _("%s - %d bytes in %.3f second response time %s|%s %s"), msg, page_len,
1375 perfd_time_firstbyte (elapsed_time_firstbyte), 1440 elapsed_time, (display_html ? "</A>" : ""), perfd_time(elapsed_time),
1376 perfd_time_transfer (elapsed_time_transfer)); 1441 perfd_size(page_len));
1377 else 1442 }
1378 xasprintf (&msg, 1443
1379 _("%s - %d bytes in %.3f second response time %s|%s %s"), 1444 if (show_body) {
1380 msg, page_len, elapsed_time, 1445 xasprintf(&msg, _("%s\n%s"), msg, page);
1381 (display_html ? "</A>" : ""), 1446 }
1382 perfd_time (elapsed_time), 1447
1383 perfd_size (page_len)); 1448 result = max_state_alt(get_status(elapsed_time, thlds), result);
1384 1449
1385 if (show_body) 1450 die(result, "HTTP %s: %s\n", state_text(result), msg);
1386 xasprintf (&msg, _("%s\n%s"), msg, page); 1451 /* die failed? */
1387 1452 return STATE_UNKNOWN;
1388 result = max_state_alt(get_status(elapsed_time, thlds), result);
1389
1390 die (result, "HTTP %s: %s\n", state_text(result), msg);
1391 /* die failed? */
1392 return STATE_UNKNOWN;
1393} 1453}
1394 1454
1395/* Receivces a pointer to the beginning of the body of a HTTP message 1455/* Receivces a pointer to the beginning of the body of a HTTP message
@@ -1398,94 +1458,95 @@ check_http (void)
1398 * The result must be freed by the caller. 1458 * The result must be freed by the caller.
1399 */ 1459 */
1400char *unchunk_content(const char *content) { 1460char *unchunk_content(const char *content) {
1401 // https://en.wikipedia.org/wiki/Chunked_transfer_encoding 1461 // https://en.wikipedia.org/wiki/Chunked_transfer_encoding
1402 // https://www.rfc-editor.org/rfc/rfc7230#section-4.1 1462 // https://www.rfc-editor.org/rfc/rfc7230#section-4.1
1403 char *result = NULL; 1463 char *result = NULL;
1404 char *start_of_chunk; 1464 char *start_of_chunk;
1405 char* end_of_chunk; 1465 char *end_of_chunk;
1406 long size_of_chunk; 1466 long size_of_chunk;
1407 const char *pointer = content; 1467 const char *pointer = content;
1408 char *endptr; 1468 char *endptr;
1409 long length_of_chunk = 0; 1469 long length_of_chunk = 0;
1410 size_t overall_size = 0; 1470 size_t overall_size = 0;
1411 1471
1412 while (true) { 1472 while (true) {
1413 size_of_chunk = strtol(pointer, &endptr, 16); 1473 size_of_chunk = strtol(pointer, &endptr, 16);
1414 if (size_of_chunk == LONG_MIN || size_of_chunk == LONG_MAX) { 1474 if (size_of_chunk == LONG_MIN || size_of_chunk == LONG_MAX) {
1415 // Apparently underflow or overflow, should not happen 1475 // Apparently underflow or overflow, should not happen
1416 if (verbose) { 1476 if (verbose) {
1417 printf("Got an underflow or overflow from strtol at: %u\n", __LINE__); 1477 printf("Got an underflow or overflow from strtol at: %u\n", __LINE__);
1418 } 1478 }
1419 return NULL; 1479 return NULL;
1420 } 1480 }
1421 if (endptr == pointer) { 1481 if (endptr == pointer) {
1422 // Apparently this was not a number 1482 // Apparently this was not a number
1423 if (verbose) { 1483 if (verbose) {
1424 printf("Chunked content did not start with a number at all (Line: %u)\n", __LINE__); 1484 printf("Chunked content did not start with a number at all (Line: %u)\n", __LINE__);
1425 } 1485 }
1426 return NULL; 1486 return NULL;
1427 } 1487 }
1428 1488
1429 // So, we got the length of the chunk 1489 // So, we got the length of the chunk
1430 if (*endptr == ';') { 1490 if (*endptr == ';') {
1431 // Chunk extension starts here 1491 // Chunk extension starts here
1432 while (*endptr != '\r') { 1492 while (*endptr != '\r') {
1433 endptr++; 1493 endptr++;
1434 } 1494 }
1435 } 1495 }
1436 1496
1437 start_of_chunk = endptr + 2; 1497 start_of_chunk = endptr + 2;
1438 end_of_chunk = start_of_chunk + size_of_chunk; 1498 end_of_chunk = start_of_chunk + size_of_chunk;
1439 length_of_chunk = (long)(end_of_chunk - start_of_chunk); 1499 length_of_chunk = (long)(end_of_chunk - start_of_chunk);
1440 pointer = end_of_chunk + 2; //Next number should be here 1500 pointer = end_of_chunk + 2; // Next number should be here
1441 1501
1442 if (length_of_chunk == 0) { 1502 if (length_of_chunk == 0) {
1443 // Chunk length is 0, so this is the last one 1503 // Chunk length is 0, so this is the last one
1444 break; 1504 break;
1445 } 1505 }
1446 1506
1447 overall_size += length_of_chunk; 1507 overall_size += length_of_chunk;
1448 1508
1449 if (result == NULL) { 1509 if (result == NULL) {
1450 // Size of the chunk plus the ending NULL byte 1510 // Size of the chunk plus the ending NULL byte
1451 result = (char *)malloc(length_of_chunk +1); 1511 result = (char *)malloc(length_of_chunk + 1);
1452 if (result == NULL) { 1512 if (result == NULL) {
1453 if (verbose) { 1513 if (verbose) {
1454 printf("Failed to allocate memory for unchunked body\n"); 1514 printf("Failed to allocate memory for unchunked body\n");
1455 } 1515 }
1456 return NULL; 1516 return NULL;
1457 } 1517 }
1458 } else { 1518 } else {
1459 // Enlarge memory to the new size plus the ending NULL byte 1519 // Enlarge memory to the new size plus the ending NULL byte
1460 void *tmp = realloc(result, overall_size +1); 1520 void *tmp = realloc(result, overall_size + 1);
1461 if (tmp == NULL) { 1521 if (tmp == NULL) {
1462 if (verbose) { 1522 if (verbose) {
1463 printf("Failed to allocate memory for unchunked body\n"); 1523 printf("Failed to allocate memory for unchunked body\n");
1464 } 1524 }
1465 return NULL; 1525 return NULL;
1466 } else { 1526 }
1467 result = tmp; 1527 result = tmp;
1468 } 1528 }
1469 } 1529
1470 1530 memcpy(result + (overall_size - size_of_chunk), start_of_chunk, size_of_chunk);
1471 memcpy(result + (overall_size - size_of_chunk), start_of_chunk, size_of_chunk); 1531 }
1472 } 1532
1473 1533 if (overall_size == 0 && result == NULL) {
1474 if (overall_size == 0 && result == NULL) { 1534 // We might just have received the end chunk without previous content, so result is never
1475 // We might just have received the end chunk without previous content, so result is never allocated 1535 // allocated
1476 result = calloc(1, sizeof(char)); 1536 result = calloc(1, sizeof(char));
1477 // No error handling here, we can only return NULL anyway 1537 // No error handling here, we can only return NULL anyway
1478 } else { 1538 } else {
1479 result[overall_size] = '\0'; 1539 result[overall_size] = '\0';
1480 } 1540 }
1481 return result; 1541 return result;
1482} 1542}
1483 1543
1484/* per RFC 2396 */ 1544/* per RFC 2396 */
1485#define URI_HTTP "%5[HTPShtps]" 1545#define URI_HTTP "%5[HTPShtps]"
1486#define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]" 1546#define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1487#define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */ 1547#define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1488#define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]" 1548#define URI_PATH \
1549 "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1489#define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH 1550#define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1490#define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH 1551#define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1491#define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT 1552#define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
@@ -1494,414 +1555,435 @@ char *unchunk_content(const char *content) {
1494#define HD5 "//" URI_HOST "/" URI_PATH 1555#define HD5 "//" URI_HOST "/" URI_PATH
1495#define HD6 URI_PATH 1556#define HD6 URI_PATH
1496 1557
1497void 1558void redir(char *pos, char *status_line) {
1498redir (char *pos, char *status_line) 1559 int i = 0;
1499{ 1560 char *x;
1500 int i = 0; 1561 char xx[2];
1501 char *x; 1562 char type[6];
1502 char xx[2]; 1563 char *addr;
1503 char type[6]; 1564 char *url;
1504 char *addr; 1565
1505 char *url; 1566 addr = malloc(MAX_IPV4_HOSTLENGTH + 1);
1506 1567 if (addr == NULL) {
1507 addr = malloc (MAX_IPV4_HOSTLENGTH + 1); 1568 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1508 if (addr == NULL) 1569 }
1509 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n")); 1570
1510 1571 memset(addr, 0, MAX_IPV4_HOSTLENGTH);
1511 memset(addr, 0, MAX_IPV4_HOSTLENGTH); 1572 url = malloc(strcspn(pos, "\r\n"));
1512 url = malloc (strcspn (pos, "\r\n")); 1573 if (url == NULL) {
1513 if (url == NULL) 1574 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1514 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 1575 }
1515 1576
1516 while (pos) { 1577 while (pos) {
1517 sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i); 1578 sscanf(pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
1518 if (i == 0) { 1579 if (i == 0) {
1519 pos += (size_t) strcspn (pos, "\r\n"); 1580 pos += (size_t)strcspn(pos, "\r\n");
1520 pos += (size_t) strspn (pos, "\r\n"); 1581 pos += (size_t)strspn(pos, "\r\n");
1521 if (strlen(pos) == 0) 1582 if (strlen(pos) == 0) {
1522 die (STATE_UNKNOWN, 1583 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1523 _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"), 1584 status_line, (display_html ? "</A>" : ""));
1524 status_line, (display_html ? "</A>" : "")); 1585 }
1525 continue; 1586 continue;
1526 } 1587 }
1527 1588
1528 pos += i; 1589 pos += i;
1529 pos += strspn (pos, " \t"); 1590 pos += strspn(pos, " \t");
1530 1591
1531 /* 1592 /*
1532 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by 1593 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by
1533 * preceding each extra line with at least one SP or HT.'' 1594 * preceding each extra line with at least one SP or HT.''
1534 */ 1595 */
1535 for (; (i = strspn (pos, "\r\n")); pos += i) { 1596 for (; (i = strspn(pos, "\r\n")); pos += i) {
1536 pos += i; 1597 pos += i;
1537 if (!(i = strspn (pos, " \t"))) { 1598 if (!(i = strspn(pos, " \t"))) {
1538 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"), 1599 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1539 display_html ? "</A>" : ""); 1600 display_html ? "</A>" : "");
1540 } 1601 }
1541 } 1602 }
1542 1603
1543 url = realloc (url, strcspn (pos, "\r\n") + 1); 1604 url = realloc(url, strcspn(pos, "\r\n") + 1);
1544 if (url == NULL) 1605 if (url == NULL) {
1545 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 1606 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1546 1607 }
1547 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */ 1608
1548 if (sscanf (pos, HD1, type, addr, &i, url) == 4) { 1609 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1549 url = prepend_slash (url); 1610 if (sscanf(pos, HD1, type, addr, &i, url) == 4) {
1550 use_ssl = server_type_check (type); 1611 url = prepend_slash(url);
1551 } 1612 use_ssl = server_type_check(type);
1552 1613 }
1553 /* URI_HTTP URI_HOST URI_PATH */ 1614
1554 else if (sscanf (pos, HD2, type, addr, url) == 3 ) { 1615 /* URI_HTTP URI_HOST URI_PATH */
1555 url = prepend_slash (url); 1616 else if (sscanf(pos, HD2, type, addr, url) == 3) {
1556 use_ssl = server_type_check (type); 1617 url = prepend_slash(url);
1557 i = server_port_check (use_ssl); 1618 use_ssl = server_type_check(type);
1558 } 1619 i = server_port_check(use_ssl);
1559 1620 }
1560 /* URI_HTTP URI_HOST URI_PORT */ 1621
1561 else if (sscanf (pos, HD3, type, addr, &i) == 3) { 1622 /* URI_HTTP URI_HOST URI_PORT */
1562 strcpy (url, HTTP_URL); 1623 else if (sscanf(pos, HD3, type, addr, &i) == 3) {
1563 use_ssl = server_type_check (type); 1624 strcpy(url, HTTP_URL);
1564 } 1625 use_ssl = server_type_check(type);
1565 1626 }
1566 /* URI_HTTP URI_HOST */ 1627
1567 else if (sscanf (pos, HD4, type, addr) == 2) { 1628 /* URI_HTTP URI_HOST */
1568 strcpy (url, HTTP_URL); 1629 else if (sscanf(pos, HD4, type, addr) == 2) {
1569 use_ssl = server_type_check (type); 1630 strcpy(url, HTTP_URL);
1570 i = server_port_check (use_ssl); 1631 use_ssl = server_type_check(type);
1571 } 1632 i = server_port_check(use_ssl);
1572 /* URI_HTTP, URI_HOST, URI_PATH */ 1633 }
1573 else if (sscanf (pos, HD5, addr, url) == 2) { 1634 /* URI_HTTP, URI_HOST, URI_PATH */
1574 if(use_ssl){ 1635 else if (sscanf(pos, HD5, addr, url) == 2) {
1575 strcpy (type,"https"); 1636 if (use_ssl) {
1576 } 1637 strcpy(type, "https");
1577 else{ 1638 } else {
1578 strcpy (type, server_type); 1639 strcpy(type, server_type);
1579 } 1640 }
1580 xasprintf (&url, "/%s", url); 1641 xasprintf(&url, "/%s", url);
1581 use_ssl = server_type_check (type); 1642 use_ssl = server_type_check(type);
1582 i = server_port_check (use_ssl); 1643 i = server_port_check(use_ssl);
1583 } 1644 }
1584 1645
1585 /* URI_PATH */ 1646 /* URI_PATH */
1586 else if (sscanf (pos, HD6, url) == 1) { 1647 else if (sscanf(pos, HD6, url) == 1) {
1587 /* relative url */ 1648 /* relative url */
1588 if ((url[0] != '/')) { 1649 if ((url[0] != '/')) {
1589 if ((x = strrchr(server_url, '/'))) 1650 if ((x = strrchr(server_url, '/'))) {
1590 *x = '\0'; 1651 *x = '\0';
1591 xasprintf (&url, "%s/%s", server_url, url); 1652 }
1592 } 1653 xasprintf(&url, "%s/%s", server_url, url);
1593 i = server_port; 1654 }
1594 strcpy (type, server_type); 1655 i = server_port;
1595 strcpy (addr, host_name ? host_name : server_address); 1656 strcpy(type, server_type);
1596 } 1657 strcpy(addr, host_name ? host_name : server_address);
1597 1658 }
1598 else { 1659
1599 die (STATE_UNKNOWN, 1660 else {
1600 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"), 1661 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"), pos,
1601 pos, (display_html ? "</A>" : "")); 1662 (display_html ? "</A>" : ""));
1602 } 1663 }
1603 1664
1604 break; 1665 break;
1605 1666
1606 } /* end while (pos) */ 1667 } /* end while (pos) */
1607 1668
1608 if (++redir_depth > max_depth) 1669 if (++redir_depth > max_depth) {
1609 die (STATE_WARNING, 1670 die(STATE_WARNING,
1610 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"), 1671 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"), max_depth,
1611 max_depth, type, addr, i, url, (display_html ? "</A>" : "")); 1672 type, addr, i, url, (display_html ? "</A>" : ""));
1612 1673 }
1613 if (server_port==i && 1674
1614 !strncmp(server_address, addr, MAX_IPV4_HOSTLENGTH) && 1675 if (server_port == i && !strncmp(server_address, addr, MAX_IPV4_HOSTLENGTH) &&
1615 (host_name && !strncmp(host_name, addr, MAX_IPV4_HOSTLENGTH)) && 1676 (host_name && !strncmp(host_name, addr, MAX_IPV4_HOSTLENGTH)) && !strcmp(server_url, url)) {
1616 !strcmp(server_url, url)) 1677 die(STATE_CRITICAL,
1617 die (STATE_CRITICAL, 1678 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), type,
1618 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), 1679 addr, i, url, (display_html ? "</A>" : ""));
1619 type, addr, i, url, (display_html ? "</A>" : "")); 1680 }
1620 1681
1621 strcpy (server_type, type); 1682 strcpy(server_type, type);
1622 1683
1623 free (host_name); 1684 free(host_name);
1624 host_name = strndup (addr, MAX_IPV4_HOSTLENGTH); 1685 host_name = strndup(addr, MAX_IPV4_HOSTLENGTH);
1625 1686
1626 if (!(followsticky & STICKY_HOST)) { 1687 if (!(followsticky & STICKY_HOST)) {
1627 free (server_address); 1688 free(server_address);
1628 server_address = strndup (addr, MAX_IPV4_HOSTLENGTH); 1689 server_address = strndup(addr, MAX_IPV4_HOSTLENGTH);
1629 } 1690 }
1630 if (!(followsticky & STICKY_PORT)) { 1691 if (!(followsticky & STICKY_PORT)) {
1631 server_port = i; 1692 server_port = i;
1632 } 1693 }
1633 1694
1634 free (server_url); 1695 free(server_url);
1635 server_url = url; 1696 server_url = url;
1636 1697
1637 if (server_port > MAX_PORT) 1698 if (server_port > MAX_PORT) {
1638 die (STATE_UNKNOWN, 1699 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1639 _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"), 1700 MAX_PORT, server_type, server_address, server_port, server_url,
1640 MAX_PORT, server_type, server_address, server_port, server_url, 1701 display_html ? "</A>" : "");
1641 display_html ? "</A>" : ""); 1702 }
1642
1643 /* reset virtual port */
1644 virtual_port = server_port;
1645
1646 if (verbose)
1647 printf (_("Redirection to %s://%s:%d%s\n"), server_type,
1648 host_name ? host_name : server_address, server_port, server_url);
1649
1650 free(addr);
1651 check_http ();
1652}
1653 1703
1704 /* reset virtual port */
1705 virtual_port = server_port;
1654 1706
1655bool 1707 if (verbose) {
1656server_type_check (const char *type) 1708 printf(_("Redirection to %s://%s:%d%s\n"), server_type,
1657{ 1709 host_name ? host_name : server_address, server_port, server_url);
1658 if (strcmp (type, "https")) 1710 }
1659 return false; 1711
1660 else 1712 free(addr);
1661 return true; 1713 check_http();
1662} 1714}
1663 1715
1664int 1716bool server_type_check(const char *type) { return (!(bool)strcmp(type, "https")); }
1665server_port_check (int ssl_flag) 1717
1666{ 1718int server_port_check(int ssl_flag) {
1667 if (ssl_flag) 1719 if (ssl_flag) {
1668 return HTTPS_PORT; 1720 return HTTPS_PORT;
1669 else 1721 }
1670 return HTTP_PORT; 1722 return HTTP_PORT;
1671} 1723}
1672 1724
1673char *perfd_time (double elapsed_time) 1725char *perfd_time(double elapsed_time) {
1674{ 1726 return fperfdata("time", elapsed_time, "s", thlds->warning,
1675 return fperfdata ("time", elapsed_time, "s", 1727 thlds->warning ? thlds->warning->end : 0, thlds->critical,
1676 thlds->warning?true:false, thlds->warning?thlds->warning->end:0, 1728 thlds->critical ? thlds->critical->end : 0, true, 0, true, socket_timeout);
1677 thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
1678 true, 0, true, socket_timeout);
1679} 1729}
1680 1730
1681char *perfd_time_connect (double elapsed_time_connect) 1731char *perfd_time_connect(double elapsed_time_connect) {
1682{ 1732 return fperfdata("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true,
1683 return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1733 socket_timeout);
1684} 1734}
1685 1735
1686char *perfd_time_ssl (double elapsed_time_ssl) 1736char *perfd_time_ssl(double elapsed_time_ssl) {
1687{ 1737 return fperfdata("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true,
1688 return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1738 socket_timeout);
1689} 1739}
1690 1740
1691char *perfd_time_headers (double elapsed_time_headers) 1741char *perfd_time_headers(double elapsed_time_headers) {
1692{ 1742 return fperfdata("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true,
1693 return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1743 socket_timeout);
1694} 1744}
1695 1745
1696char *perfd_time_firstbyte (double elapsed_time_firstbyte) 1746char *perfd_time_firstbyte(double elapsed_time_firstbyte) {
1697{ 1747 return fperfdata("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0,
1698 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1748 true, socket_timeout);
1699} 1749}
1700 1750
1701char *perfd_time_transfer (double elapsed_time_transfer) 1751char *perfd_time_transfer(double elapsed_time_transfer) {
1702{ 1752 return fperfdata("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0,
1703 return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1753 true, socket_timeout);
1704} 1754}
1705 1755
1706char *perfd_size (int page_len) 1756char *perfd_size(int page_len) {
1707{ 1757 return perfdata("size", page_len, "B", (min_page_len > 0), min_page_len, (min_page_len > 0), 0,
1708 return perfdata ("size", page_len, "B", 1758 true, 0, false, 0);
1709 (min_page_len>0?true:false), min_page_len,
1710 (min_page_len>0?true:false), 0,
1711 true, 0, false, 0);
1712} 1759}
1713 1760
1714void 1761void print_help(void) {
1715print_help (void) 1762 print_revision(progname, NP_VERSION);
1716{
1717 print_revision (progname, NP_VERSION);
1718 1763
1719 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 1764 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1720 printf (COPYRIGHT, copyright, email); 1765 printf(COPYRIGHT, copyright, email);
1721 1766
1722 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test")); 1767 printf("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1723 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for")); 1768 printf("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1724 printf ("%s\n", _("strings and regular expressions, check connection times, and report on")); 1769 printf("%s\n", _("strings and regular expressions, check connection times, and report on"));
1725 printf ("%s\n", _("certificate expiration times.")); 1770 printf("%s\n", _("certificate expiration times."));
1726 1771
1727 printf ("\n\n"); 1772 printf("\n");
1773 printf("%s\n", _("ATTENTION!"));
1774 printf("\n");
1775 printf("%s\n", _("THIS PLUGIN IS DEPRECATED. The functionality was reimplemented by the"));
1776 printf("%s\n", _("check_curl plugin, which can be used as a drop-in replacement. You should"));
1777 printf("%s\n", _("migrate your checks over to check_curl, because check_http is going to be"));
1778 printf("%s\n", _("removed sooner than later. Just replace check_http with check_curl in your"));
1779 printf("%s\n", _("check command definitions."));
1780 printf("%s\n",
1781 _("Report issues to: https://github.com/monitoring-plugins/monitoring-plugins/issues"));
1728 1782
1729 print_usage (); 1783 printf("\n\n");
1784
1785 print_usage();
1730 1786
1731#ifdef HAVE_SSL 1787#ifdef HAVE_SSL
1732 printf (_("In the first form, make an HTTP request.")); 1788 printf(_("In the first form, make an HTTP request."));
1733 printf (_("In the second form, connect to the server and check the TLS certificate.")); 1789 printf(_("In the second form, connect to the server and check the TLS certificate."));
1734#endif 1790#endif
1735 printf (_("NOTE: One or both of -H and -I must be specified")); 1791 printf(_("NOTE: One or both of -H and -I must be specified"));
1736 1792
1737 printf ("\n"); 1793 printf("\n");
1738 1794
1739 printf (UT_HELP_VRSN); 1795 printf(UT_HELP_VRSN);
1740 printf (UT_EXTRA_OPTS); 1796 printf(UT_EXTRA_OPTS);
1741 1797
1742 printf (" %s\n", "-H, --hostname=ADDRESS"); 1798 printf(" %s\n", "-H, --hostname=ADDRESS");
1743 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)")); 1799 printf(" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1744 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)")); 1800 printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1745 printf (" %s\n", "-I, --IP-address=ADDRESS"); 1801 printf(" %s\n", "-I, --IP-address=ADDRESS");
1746 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup).")); 1802 printf(" %s\n",
1747 printf (" %s\n", "-p, --port=INTEGER"); 1803 _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1748 printf (" %s", _("Port number (default: ")); 1804 printf(" %s\n", "-p, --port=INTEGER");
1749 printf ("%d)\n", HTTP_PORT); 1805 printf(" %s", _("Port number (default: "));
1806 printf("%d)\n", HTTP_PORT);
1750 1807
1751 printf (UT_IPv46); 1808 printf(UT_IPv46);
1752 1809
1753#ifdef HAVE_SSL 1810#ifdef HAVE_SSL
1754 printf (" %s\n", "-S, --ssl=VERSION[+]"); 1811 printf(" %s\n", "-S, --ssl=VERSION[+]");
1755 printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents")); 1812 printf(" %s\n",
1756 printf (" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,")); 1813 _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
1757 printf (" %s\n", _("1.2 = TLSv1.2). With a '+' suffix, newer versions are also accepted.")); 1814 printf(" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,"));
1758 printf (" %s\n", "--sni"); 1815 printf(" %s\n", _("1.2 = TLSv1.2). With a '+' suffix, newer versions are also accepted."));
1759 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 1816 printf(" %s\n", "--sni");
1760 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]"); 1817 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
1761 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443")); 1818 printf(" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
1762 printf (" %s\n", _("(when this option is used the URL is not checked by default. You can use")); 1819 printf(" %s\n",
1763 printf (" %s\n", _(" --continue-after-certificate to override this behavior)")); 1820 _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1764 printf (" %s\n", "--continue-after-certificate"); 1821 printf(" %s\n",
1765 printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check.")); 1822 _("(when this option is used the URL is not checked by default. You can use"));
1766 printf (" %s\n", _("Does nothing unless -C is used.")); 1823 printf(" %s\n", _(" --continue-after-certificate to override this behavior)"));
1767 printf (" %s\n", "-J, --client-cert=FILE"); 1824 printf(" %s\n", "--continue-after-certificate");
1768 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)")); 1825 printf(" %s\n",
1769 printf (" %s\n", _("to be used in establishing the SSL session")); 1826 _("Allows the HTTP check to continue after performing the certificate check."));
1770 printf (" %s\n", "-K, --private-key=FILE"); 1827 printf(" %s\n", _("Does nothing unless -C is used."));
1771 printf (" %s\n", _("Name of file containing the private key (PEM format)")); 1828 printf(" %s\n", "-J, --client-cert=FILE");
1772 printf (" %s\n", _("matching the client certificate")); 1829 printf(" %s\n", _("Name of file that contains the client certificate (PEM format)"));
1830 printf(" %s\n", _("to be used in establishing the SSL session"));
1831 printf(" %s\n", "-K, --private-key=FILE");
1832 printf(" %s\n", _("Name of file containing the private key (PEM format)"));
1833 printf(" %s\n", _("matching the client certificate"));
1773#endif 1834#endif
1774 1835
1775 printf (" %s\n", "-e, --expect=STRING"); 1836 printf(" %s\n", "-e, --expect=STRING");
1776 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in")); 1837 printf(" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
1777 printf (" %s", _("the first (status) line of the server response (default: ")); 1838 printf(" %s", _("the first (status) line of the server response (default: "));
1778 printf ("%s)\n", HTTP_EXPECT); 1839 printf("%s)\n", HTTP_EXPECT);
1779 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)")); 1840 printf(" %s\n",
1780 printf (" %s\n", "-d, --header-string=STRING"); 1841 _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1781 printf (" %s\n", _("String to expect in the response headers")); 1842 printf(" %s\n", "-d, --header-string=STRING");
1782 printf (" %s\n", "-s, --string=STRING"); 1843 printf(" %s\n", _("String to expect in the response headers"));
1783 printf (" %s\n", _("String to expect in the content")); 1844 printf(" %s\n", "-s, --string=STRING");
1784 printf (" %s\n", "-u, --url=PATH"); 1845 printf(" %s\n", _("String to expect in the content"));
1785 printf (" %s\n", _("URL to GET or POST (default: /)")); 1846 printf(" %s\n", "-u, --url=PATH");
1786 printf (" %s\n", "-P, --post=STRING"); 1847 printf(" %s\n", _("URL to GET or POST (default: /)"));
1787 printf (" %s\n", _("URL decoded http POST data")); 1848 printf(" %s\n", "-P, --post=STRING");
1788 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT, CONNECT:POST)"); 1849 printf(" %s\n", _("URL decoded http POST data"));
1789 printf (" %s\n", _("Set HTTP method.")); 1850 printf(" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, "
1790 printf (" %s\n", "-N, --no-body"); 1851 "CONNECT, CONNECT:POST)");
1791 printf (" %s\n", _("Don't wait for document body: stop reading after headers.")); 1852 printf(" %s\n", _("Set HTTP method."));
1792 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)")); 1853 printf(" %s\n", "-N, --no-body");
1793 printf (" %s\n", "-M, --max-age=SECONDS"); 1854 printf(" %s\n", _("Don't wait for document body: stop reading after headers."));
1794 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of")); 1855 printf(" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1795 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.")); 1856 printf(" %s\n", "-M, --max-age=SECONDS");
1796 printf (" %s\n", "-T, --content-type=STRING"); 1857 printf(" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1797 printf (" %s\n", _("specify Content-Type header media type when POSTing\n")); 1858 printf(" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1798 1859 printf(" %s\n", "-T, --content-type=STRING");
1799 printf (" %s\n", "-l, --linespan"); 1860 printf(" %s\n", _("specify Content-Type header media type when POSTing\n"));
1800 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)")); 1861
1801 printf (" %s\n", "-r, --regex, --ereg=STRING"); 1862 printf(" %s\n", "-l, --linespan");
1802 printf (" %s\n", _("Search page for regex STRING")); 1863 printf(" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1803 printf (" %s\n", "-R, --eregi=STRING"); 1864 printf(" %s\n", "-r, --regex, --ereg=STRING");
1804 printf (" %s\n", _("Search page for case-insensitive regex STRING")); 1865 printf(" %s\n", _("Search page for regex STRING"));
1805 printf (" %s\n", "--invert-regex"); 1866 printf(" %s\n", "-R, --eregi=STRING");
1806 printf (" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)")); 1867 printf(" %s\n", _("Search page for case-insensitive regex STRING"));
1807 printf (" %s\n", _("can be changed with --state--regex)")); 1868 printf(" %s\n", "--invert-regex");
1808 printf (" %s\n", "--regex-state=STATE"); 1869 printf(" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)"));
1809 printf (" %s\n", _("Return STATE if regex is found, OK if not\n")); 1870 printf(" %s\n", _("can be changed with --state--regex)"));
1810 1871 printf(" %s\n", "--state-regex=STATE");
1811 printf (" %s\n", "-a, --authorization=AUTH_PAIR"); 1872 printf(" %s\n", _("Return STATE if regex is found, OK if not\n"));
1812 printf (" %s\n", _("Username:password on sites with basic authentication")); 1873
1813 printf (" %s\n", "-b, --proxy-authorization=AUTH_PAIR"); 1874 printf(" %s\n", "-a, --authorization=AUTH_PAIR");
1814 printf (" %s\n", _("Username:password on proxy-servers with basic authentication")); 1875 printf(" %s\n", _("Username:password on sites with basic authentication"));
1815 printf (" %s\n", "-A, --useragent=STRING"); 1876 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
1816 printf (" %s\n", _("String to be sent in http header as \"User Agent\"")); 1877 printf(" %s\n", _("Username:password on proxy-servers with basic authentication"));
1817 printf (" %s\n", "-k, --header=STRING"); 1878 printf(" %s\n", "-A, --useragent=STRING");
1818 printf (" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers")); 1879 printf(" %s\n", _("String to be sent in http header as \"User Agent\""));
1819 printf (" %s\n", "-E, --extended-perfdata"); 1880 printf(" %s\n", "-k, --header=STRING");
1820 printf (" %s\n", _("Print additional performance data")); 1881 printf(
1821 printf (" %s\n", "-B, --show-body"); 1882 " %s\n",
1822 printf (" %s\n", _("Print body content below status line")); 1883 _("Any other tags to be sent in http header. Use multiple times for additional headers"));
1823 printf (" %s\n", "-L, --link"); 1884 printf(" %s\n", "-E, --extended-perfdata");
1824 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)")); 1885 printf(" %s\n", _("Print additional performance data"));
1825 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>"); 1886 printf(" %s\n", "-B, --show-body");
1826 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the")); 1887 printf(" %s\n", _("Print body content below status line"));
1827 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same.")); 1888 printf(" %s\n", "-L, --link");
1828 printf (" %s\n", "--max-redirs=INTEGER"); 1889 printf(" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1829 printf (" %s", _("Maximal number of redirects (default: ")); 1890 printf(" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>");
1830 printf ("%d)\n", DEFAULT_MAX_REDIRS); 1891 printf(" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
1831 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); 1892 printf(" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
1832 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); 1893 printf(" %s\n", "--max-redirs=INTEGER");
1833 printf (UT_WARN_CRIT); 1894 printf(" %s", _("Maximal number of redirects (default: "));
1834 1895 printf("%d)\n", DEFAULT_MAX_REDIRS);
1835 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 1896 printf(" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1836 1897 printf(" %s\n",
1837 printf (UT_VERBOSE); 1898 _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1838 1899 printf(UT_WARN_CRIT);
1839 printf ("\n"); 1900
1840 printf ("%s\n", _("Notes:")); 1901 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1841 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host.")); 1902
1842 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL")); 1903 printf(" %s\n", "--timeout-result=ok|warning|critical|unknown|0|1|2|3");
1843 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response")); 1904 printf(" %s\n", _("Timeouts default to returning STATE_CRITICAL."));
1844 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are")); 1905 printf(" %s\n", _("This argument changes the return state on timeouts."));
1845 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN")); 1906
1846 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument.")); 1907 printf(UT_VERBOSE);
1908
1909 printf("\n");
1910 printf("%s\n", _("Notes:"));
1911 printf(" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1912 printf(" %s\n",
1913 _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1914 printf(" %s\n",
1915 _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response"));
1916 printf(" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1917 printf(" %s\n",
1918 _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1919 printf(" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1847 1920
1848#ifdef HAVE_SSL 1921#ifdef HAVE_SSL
1849 printf ("\n"); 1922 printf("\n");
1850 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to")); 1923 printf(" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1851 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 ")); 1924 printf(" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1852 printf (" %s\n", _("certificate is still valid for the specified number of days.")); 1925 printf(" %s\n", _("certificate is still valid for the specified number of days."));
1853 printf ("\n"); 1926 printf("\n");
1854 printf (" %s\n", _("Please note that this plugin does not check if the presented server")); 1927 printf(" %s\n", _("Please note that this plugin does not check if the presented server"));
1855 printf (" %s\n", _("certificate matches the hostname of the server, or if the certificate")); 1928 printf(" %s\n", _("certificate matches the hostname of the server, or if the certificate"));
1856 printf (" %s\n", _("has a valid chain of trust to one of the locally installed CAs.")); 1929 printf(" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
1857 printf ("\n"); 1930 printf("\n");
1858 printf ("%s\n", _("Examples:")); 1931 printf("%s\n", _("Examples:"));
1859 printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com"); 1932 printf(" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1860 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,")); 1933 printf(" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1861 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 1934 printf(" %s\n",
1862 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 1935 _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1863 printf (" %s\n", _("a STATE_CRITICAL will be returned.")); 1936 printf(" %s\n",
1864 printf ("\n"); 1937 _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1865 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14"); 1938 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
1866 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,")); 1939 printf("\n");
1867 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 1940 printf(" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1868 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when")); 1941 printf(" %s\n",
1869 printf (" %s\n\n", _("the certificate is expired.")); 1942 _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1870 printf ("\n"); 1943 printf(" %s\n",
1871 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 30,14"); 1944 _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1872 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,")); 1945 printf(" %s\n",
1873 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 1946 _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1874 printf (" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned.")); 1947 printf(" %s\n\n", _("the certificate is expired."));
1875 printf (" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days")); 1948 printf("\n");
1876 1949 printf(" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 30,14");
1877 printf (" %s\n\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: "); 1950 printf(" %s\n",
1878 printf (" %s\n", _("check_http -I 192.168.100.35 -p 80 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com ")); 1951 _("When the certificate of 'www.verisign.com' is valid for more than 30 days,"));
1879 printf (" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>")); 1952 printf(" %s\n",
1880 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 1953 _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1881 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 1954 printf(" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned."));
1882 printf (" %s\n", _("a STATE_CRITICAL will be returned. By adding a colon to the method you can set the method used")); 1955 printf(" %s\n",
1883 printf (" %s\n", _("inside the proxied connection: -j CONNECT:POST")); 1956 _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
1957
1958 printf(" %s\n\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: ");
1959 printf(" %s\n", _("check_http -I 192.168.100.35 -p 80 -u https://www.verisign.com/ -S -j "
1960 "CONNECT -H www.verisign.com "));
1961 printf(" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> "
1962 "-S(sl) -j CONNECT -H <webserver>"));
1963 printf(" %s\n",
1964 _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1965 printf(" %s\n",
1966 _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1967 printf(" %s\n", _("a STATE_CRITICAL will be returned. By adding a colon to the method you can "
1968 "set the method used"));
1969 printf(" %s\n", _("inside the proxied connection: -j CONNECT:POST"));
1884 1970
1885#endif 1971#endif
1886 1972
1887 printf (UT_SUPPORT); 1973 printf(UT_SUPPORT);
1888
1889} 1974}
1890 1975
1891 1976void print_usage(void) {
1892 1977 printf("%s\n", _("Usage:"));
1893void 1978 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname);
1894print_usage (void) 1979 printf(" [-J <client certificate file>] [-K <private key>]\n");
1895{ 1980 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
1896 printf ("%s\n", _("Usage:")); 1981 printf(" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport>]\n");
1897 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname); 1982 printf(" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive "
1898 printf (" [-J <client certificate file>] [-K <private key>]\n"); 1983 "regex>]\n");
1899 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); 1984 printf(" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
1900 printf (" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport>]\n"); 1985 printf(" [-A string] [-k string] [-S <version>] [--sni]\n");
1901 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); 1986 printf(" [-T <content-type>] [-j method]\n");
1902 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); 1987 printf(" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n", progname);
1903 printf (" [-A string] [-k string] [-S <version>] [--sni]\n"); 1988 printf(" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
1904 printf (" [-T <content-type>] [-j method]\n");
1905 printf (" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n",progname);
1906 printf (" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
1907} 1989}