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