summaryrefslogtreecommitdiffstats
path: root/plugins/check_curl.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_curl.c')
-rw-r--r--plugins/check_curl.c4596
1 files changed, 2241 insertions, 2355 deletions
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index d3bddac..1d27da2 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -1,40 +1,40 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_curl plugin 3 * Monitoring check_curl plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2019 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_curl plugin 10 * This file contains the check_curl 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* This plugin uses functions from the curl library, see 17 * This plugin uses functions from the curl library, see
18* http://curl.haxx.se 18 * http://curl.haxx.se
19* 19 *
20* This program is free software: you can redistribute it and/or modify 20 * This program is free software: you can redistribute it and/or modify
21* it under the terms of the GNU General Public License as published by 21 * it under the terms of the GNU General Public License as published by
22* the Free Software Foundation, either version 3 of the License, or 22 * the Free Software Foundation, either version 3 of the License, or
23* (at your option) any later version. 23 * (at your option) any later version.
24* 24 *
25* This program is distributed in the hope that it will be useful, 25 * This program is distributed in the hope that it will be useful,
26* but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28* GNU General Public License for more details. 28 * GNU General Public License for more details.
29* 29 *
30* You should have received a copy of the GNU General Public License 30 * You should have received a copy of the GNU General Public License
31* along with this program. If not, see <http://www.gnu.org/licenses/>. 31 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32* 32 *
33* 33 *
34*****************************************************************************/ 34 *****************************************************************************/
35const char *progname = "check_curl"; 35const char *progname = "check_curl";
36 36
37const char *copyright = "2006-2019"; 37const char *copyright = "2006-2024";
38const char *email = "devel@monitoring-plugins.org"; 38const char *email = "devel@monitoring-plugins.org";
39 39
40#include <stdbool.h> 40#include <stdbool.h>
@@ -44,7 +44,7 @@ const char *email = "devel@monitoring-plugins.org";
44#include "utils.h" 44#include "utils.h"
45 45
46#ifndef LIBCURL_PROTOCOL_HTTP 46#ifndef LIBCURL_PROTOCOL_HTTP
47#error libcurl compiled without HTTP support, compiling check_curl plugin does not makes a lot of sense 47# error libcurl compiled without HTTP support, compiling check_curl plugin does not makes a lot of sense
48#endif 48#endif
49 49
50#include "curl/curl.h" 50#include "curl/curl.h"
@@ -58,7 +58,7 @@ const char *email = "devel@monitoring-plugins.org";
58#include <netinet/in.h> 58#include <netinet/in.h>
59 59
60#if defined(HAVE_SSL) && defined(USE_OPENSSL) 60#if defined(HAVE_SSL) && defined(USE_OPENSSL)
61#include <openssl/opensslv.h> 61# include <openssl/opensslv.h>
62#endif 62#endif
63 63
64#include <netdb.h> 64#include <netdb.h>
@@ -66,1107 +66,1049 @@ const char *email = "devel@monitoring-plugins.org";
66#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch)) 66#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch))
67 67
68#define DEFAULT_BUFFER_SIZE 2048 68#define DEFAULT_BUFFER_SIZE 2048
69#define DEFAULT_SERVER_URL "/" 69#define DEFAULT_SERVER_URL "/"
70#define HTTP_EXPECT "HTTP/" 70#define HTTP_EXPECT "HTTP/"
71#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN 71#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
72enum { 72enum {
73 MAX_IPV4_HOSTLENGTH = 255, 73 MAX_IPV4_HOSTLENGTH = 255,
74 HTTP_PORT = 80, 74 HTTP_PORT = 80,
75 HTTPS_PORT = 443, 75 HTTPS_PORT = 443,
76 MAX_PORT = 65535, 76 MAX_PORT = 65535,
77 DEFAULT_MAX_REDIRS = 15 77 DEFAULT_MAX_REDIRS = 15
78}; 78};
79 79
80enum { 80enum {
81 STICKY_NONE = 0, 81 STICKY_NONE = 0,
82 STICKY_HOST = 1, 82 STICKY_HOST = 1,
83 STICKY_PORT = 2 83 STICKY_PORT = 2
84}; 84};
85 85
86enum { 86enum {
87 FOLLOW_HTTP_CURL = 0, 87 FOLLOW_HTTP_CURL = 0,
88 FOLLOW_LIBCURL = 1 88 FOLLOW_LIBCURL = 1
89}; 89};
90 90
91/* for buffers for header and body */ 91/* for buffers for header and body */
92typedef struct { 92typedef struct {
93 char *buf; 93 char *buf;
94 size_t buflen; 94 size_t buflen;
95 size_t bufsize; 95 size_t bufsize;
96} curlhelp_write_curlbuf; 96} curlhelp_write_curlbuf;
97 97
98/* for buffering the data sent in PUT */ 98/* for buffering the data sent in PUT */
99typedef struct { 99typedef struct {
100 char *buf; 100 char *buf;
101 size_t buflen; 101 size_t buflen;
102 off_t pos; 102 off_t pos;
103} curlhelp_read_curlbuf; 103} curlhelp_read_curlbuf;
104 104
105/* for parsing the HTTP status line */ 105/* for parsing the HTTP status line */
106typedef struct { 106typedef struct {
107 int http_major; /* major version of the protocol, always 1 (HTTP/0.9 107 int http_major; /* major version of the protocol, always 1 (HTTP/0.9
108 * never reached the big internet most likely) */ 108 * never reached the big internet most likely) */
109 int http_minor; /* minor version of the protocol, usually 0 or 1 */ 109 int http_minor; /* minor version of the protocol, usually 0 or 1 */
110 int http_code; /* HTTP return code as in RFC 2145 */ 110 int http_code; /* HTTP return code as in RFC 2145 */
111 int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see 111 int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see
112 * http://support.microsoft.com/kb/318380/en-us */ 112 * http://support.microsoft.com/kb/318380/en-us */
113 const char *msg; /* the human readable message */ 113 const char *msg; /* the human readable message */
114 char *first_line; /* a copy of the first line */ 114 char *first_line; /* a copy of the first line */
115} curlhelp_statusline; 115} curlhelp_statusline;
116 116
117/* to know the underlying SSL library used by libcurl */ 117/* to know the underlying SSL library used by libcurl */
118typedef enum curlhelp_ssl_library { 118typedef enum curlhelp_ssl_library {
119 CURLHELP_SSL_LIBRARY_UNKNOWN, 119 CURLHELP_SSL_LIBRARY_UNKNOWN,
120 CURLHELP_SSL_LIBRARY_OPENSSL, 120 CURLHELP_SSL_LIBRARY_OPENSSL,
121 CURLHELP_SSL_LIBRARY_LIBRESSL, 121 CURLHELP_SSL_LIBRARY_LIBRESSL,
122 CURLHELP_SSL_LIBRARY_GNUTLS, 122 CURLHELP_SSL_LIBRARY_GNUTLS,
123 CURLHELP_SSL_LIBRARY_NSS 123 CURLHELP_SSL_LIBRARY_NSS
124} curlhelp_ssl_library; 124} curlhelp_ssl_library;
125 125
126enum { 126enum {
127 REGS = 2, 127 REGS = 2,
128 MAX_RE_SIZE = 1024 128 MAX_RE_SIZE = 1024
129}; 129};
130#include "regex.h" 130#include "regex.h"
131regex_t preg; 131static regex_t preg;
132regmatch_t pmatch[REGS]; 132static regmatch_t pmatch[REGS];
133char regexp[MAX_RE_SIZE]; 133static char regexp[MAX_RE_SIZE];
134int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE; 134static int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
135int errcode; 135static int errcode;
136bool invert_regex = false; 136static bool invert_regex = false;
137int state_regex = STATE_CRITICAL; 137static int state_regex = STATE_CRITICAL;
138 138
139char *server_address = NULL; 139static char *server_address = NULL;
140char *host_name = NULL; 140static char *host_name = NULL;
141char *server_url = 0; 141static char *server_url = 0;
142char server_ip[DEFAULT_BUFFER_SIZE]; 142static struct curl_slist *server_ips = NULL;
143struct curl_slist *server_ips = NULL; 143static bool specify_port = false;
144bool specify_port = false; 144static unsigned short server_port = HTTP_PORT;
145unsigned short server_port = HTTP_PORT; 145static unsigned short virtual_port = 0;
146unsigned short virtual_port = 0; 146static int host_name_length;
147int host_name_length; 147static char output_header_search[30] = "";
148char output_header_search[30] = ""; 148static char output_string_search[30] = "";
149char output_string_search[30] = ""; 149static char *warning_thresholds = NULL;
150char *warning_thresholds = NULL; 150static char *critical_thresholds = NULL;
151char *critical_thresholds = NULL; 151static int days_till_exp_warn, days_till_exp_crit;
152int days_till_exp_warn, days_till_exp_crit; 152static thresholds *thlds;
153thresholds *thlds; 153static char user_agent[DEFAULT_BUFFER_SIZE];
154char user_agent[DEFAULT_BUFFER_SIZE]; 154static int verbose = 0;
155int verbose = 0; 155static bool show_extended_perfdata = false;
156bool show_extended_perfdata = false; 156static bool show_body = false;
157bool show_body = false; 157static int min_page_len = 0;
158int min_page_len = 0; 158static int max_page_len = 0;
159int max_page_len = 0; 159static int redir_depth = 0;
160int redir_depth = 0; 160static int max_depth = DEFAULT_MAX_REDIRS;
161int max_depth = DEFAULT_MAX_REDIRS; 161static char *http_method = NULL;
162char *http_method = NULL; 162static char *http_post_data = NULL;
163char *http_post_data = NULL; 163static char *http_content_type = NULL;
164char *http_content_type = NULL; 164static CURL *curl;
165CURL *curl; 165static bool curl_global_initialized = false;
166bool curl_global_initialized = false; 166static bool curl_easy_initialized = false;
167bool curl_easy_initialized = false; 167static struct curl_slist *header_list = NULL;
168struct curl_slist *header_list = NULL; 168static bool body_buf_initialized = false;
169bool body_buf_initialized = false; 169static curlhelp_write_curlbuf body_buf;
170curlhelp_write_curlbuf body_buf; 170static bool header_buf_initialized = false;
171bool header_buf_initialized = false; 171static curlhelp_write_curlbuf header_buf;
172curlhelp_write_curlbuf header_buf; 172static bool status_line_initialized = false;
173bool status_line_initialized = false; 173static curlhelp_statusline status_line;
174curlhelp_statusline status_line; 174static bool put_buf_initialized = false;
175bool put_buf_initialized = false; 175static curlhelp_read_curlbuf put_buf;
176curlhelp_read_curlbuf put_buf; 176static char http_header[DEFAULT_BUFFER_SIZE];
177char http_header[DEFAULT_BUFFER_SIZE]; 177static long code;
178long code; 178static long socket_timeout = DEFAULT_SOCKET_TIMEOUT;
179long socket_timeout = DEFAULT_SOCKET_TIMEOUT; 179static double total_time;
180double total_time; 180static double time_connect;
181double time_connect; 181static double time_appconnect;
182double time_appconnect; 182static double time_headers;
183double time_headers; 183static double time_firstbyte;
184double time_firstbyte; 184static char errbuf[MAX_INPUT_BUFFER];
185char errbuf[MAX_INPUT_BUFFER]; 185static CURLcode res;
186CURLcode res; 186static char url[DEFAULT_BUFFER_SIZE];
187char url[DEFAULT_BUFFER_SIZE]; 187static char msg[DEFAULT_BUFFER_SIZE];
188char msg[DEFAULT_BUFFER_SIZE]; 188static char perfstring[DEFAULT_BUFFER_SIZE];
189char perfstring[DEFAULT_BUFFER_SIZE]; 189static char header_expect[MAX_INPUT_BUFFER] = "";
190char header_expect[MAX_INPUT_BUFFER] = ""; 190static char string_expect[MAX_INPUT_BUFFER] = "";
191char string_expect[MAX_INPUT_BUFFER] = ""; 191static char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
192char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT; 192static int server_expect_yn = 0;
193int server_expect_yn = 0; 193static char user_auth[MAX_INPUT_BUFFER] = "";
194char user_auth[MAX_INPUT_BUFFER] = ""; 194static char proxy_auth[MAX_INPUT_BUFFER] = "";
195char proxy_auth[MAX_INPUT_BUFFER] = ""; 195static char **http_opt_headers;
196char **http_opt_headers; 196static int http_opt_headers_count = 0;
197int http_opt_headers_count = 0; 197static bool display_html = false;
198bool display_html = false; 198static int onredirect = STATE_OK;
199int onredirect = STATE_OK; 199static int followmethod = FOLLOW_HTTP_CURL;
200int followmethod = FOLLOW_HTTP_CURL; 200static int followsticky = STICKY_NONE;
201int followsticky = STICKY_NONE; 201static bool use_ssl = false;
202bool use_ssl = false; 202static bool check_cert = false;
203bool use_sni = true; 203static bool continue_after_check_cert = false;
204bool check_cert = false;
205bool continue_after_check_cert = false;
206typedef union { 204typedef union {
207 struct curl_slist* to_info; 205 struct curl_slist *to_info;
208 struct curl_certinfo* to_certinfo; 206 struct curl_certinfo *to_certinfo;
209} cert_ptr_union; 207} cert_ptr_union;
210cert_ptr_union cert_ptr; 208static cert_ptr_union cert_ptr;
211int ssl_version = CURL_SSLVERSION_DEFAULT; 209static int ssl_version = CURL_SSLVERSION_DEFAULT;
212char *client_cert = NULL; 210static char *client_cert = NULL;
213char *client_privkey = NULL; 211static char *client_privkey = NULL;
214char *ca_cert = NULL; 212static char *ca_cert = NULL;
215bool verify_peer_and_host = false; 213static bool verify_peer_and_host = false;
216bool is_openssl_callback = false; 214static bool is_openssl_callback = false;
217bool add_sslctx_verify_fun = false; 215static bool add_sslctx_verify_fun = false;
218#if defined(HAVE_SSL) && defined(USE_OPENSSL) 216#if defined(HAVE_SSL) && defined(USE_OPENSSL)
219X509 *cert = NULL; 217static X509 *cert = NULL;
220#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ 218#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
221bool no_body = false; 219static bool no_body = false;
222int maximum_age = -1; 220static int maximum_age = -1;
223int address_family = AF_UNSPEC; 221static int address_family = AF_UNSPEC;
224curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; 222static curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
225int curl_http_version = CURL_HTTP_VERSION_NONE; 223static int curl_http_version = CURL_HTTP_VERSION_NONE;
226bool automatic_decompression = false; 224static bool automatic_decompression = false;
227char *cookie_jar_file = NULL; 225static char *cookie_jar_file = NULL;
228bool haproxy_protocol = false; 226static bool haproxy_protocol = false;
229 227
230bool process_arguments (int, char**); 228static bool process_arguments(int /*argc*/, char ** /*argv*/);
231void handle_curl_option_return_code (CURLcode res, const char* option); 229static void handle_curl_option_return_code(CURLcode res, const char *option);
232int check_http (void); 230static int check_http(void);
233void redir (curlhelp_write_curlbuf*); 231static void redir(curlhelp_write_curlbuf * /*header_buf*/);
234char *perfd_time (double microsec); 232static char *perfd_time(double elapsed_time);
235char *perfd_time_connect (double microsec); 233static char *perfd_time_connect(double elapsed_time_connect);
236char *perfd_time_ssl (double microsec); 234static char *perfd_time_ssl(double elapsed_time_ssl);
237char *perfd_time_firstbyte (double microsec); 235static char *perfd_time_firstbyte(double elapsed_time_firstbyte);
238char *perfd_time_headers (double microsec); 236static char *perfd_time_headers(double elapsed_time_headers);
239char *perfd_time_transfer (double microsec); 237static char *perfd_time_transfer(double elapsed_time_transfer);
240char *perfd_size (int page_len); 238static char *perfd_size(int page_len);
241void print_help (void); 239static void print_help(void);
242void print_usage (void); 240void print_usage(void);
243void print_curl_version (void); 241static void print_curl_version(void);
244int curlhelp_initwritebuffer (curlhelp_write_curlbuf*); 242static int curlhelp_initwritebuffer(curlhelp_write_curlbuf * /*buf*/);
245size_t curlhelp_buffer_write_callback(void*, size_t , size_t , void*); 243static size_t curlhelp_buffer_write_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, void * /*stream*/);
246void curlhelp_freewritebuffer (curlhelp_write_curlbuf*); 244static void curlhelp_freewritebuffer(curlhelp_write_curlbuf * /*buf*/);
247int curlhelp_initreadbuffer (curlhelp_read_curlbuf *, const char *, size_t); 245static int curlhelp_initreadbuffer(curlhelp_read_curlbuf * /*buf*/, const char * /*data*/, size_t /*datalen*/);
248size_t curlhelp_buffer_read_callback(void *, size_t , size_t , void *); 246static size_t curlhelp_buffer_read_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, void * /*stream*/);
249void curlhelp_freereadbuffer (curlhelp_read_curlbuf *); 247static void curlhelp_freereadbuffer(curlhelp_read_curlbuf * /*buf*/);
250curlhelp_ssl_library curlhelp_get_ssl_library (); 248static curlhelp_ssl_library curlhelp_get_ssl_library(void);
251const char* curlhelp_get_ssl_library_string (curlhelp_ssl_library); 249static const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library /*ssl_library*/);
252int net_noopenssl_check_certificate (cert_ptr_union*, int, int); 250int net_noopenssl_check_certificate(cert_ptr_union *, int, int);
253 251
254int curlhelp_parse_statusline (const char*, curlhelp_statusline *); 252static int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/);
255void curlhelp_free_statusline (curlhelp_statusline *); 253static void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/);
256char *get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header); 254static char *get_header_value(const struct phr_header *headers, size_t nof_headers, const char *header);
257int check_document_dates (const curlhelp_write_curlbuf *, char (*msg)[DEFAULT_BUFFER_SIZE]); 255static int check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/, char (*msg)[DEFAULT_BUFFER_SIZE]);
258int get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_write_curlbuf* body_buf); 256static int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf);
259 257
260#if defined(HAVE_SSL) && defined(USE_OPENSSL) 258#if defined(HAVE_SSL) && defined(USE_OPENSSL)
261int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit); 259int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit);
262#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ 260#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
263 261
264void remove_newlines (char *); 262static void test_file(char * /*path*/);
265void test_file (char *);
266 263
267int 264int main(int argc, char **argv) {
268main (int argc, char **argv) 265 int result = STATE_UNKNOWN;
269{
270 int result = STATE_UNKNOWN;
271 266
272 setlocale (LC_ALL, ""); 267 setlocale(LC_ALL, "");
273 bindtextdomain (PACKAGE, LOCALEDIR); 268 bindtextdomain(PACKAGE, LOCALEDIR);
274 textdomain (PACKAGE); 269 textdomain(PACKAGE);
275 270
276 /* Parse extra opts if any */ 271 /* Parse extra opts if any */
277 argv = np_extra_opts (&argc, argv, progname); 272 argv = np_extra_opts(&argc, argv, progname);
278 273
279 /* set defaults */ 274 /* set defaults */
280 snprintf( user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)", 275 snprintf(user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)", progname, NP_VERSION, VERSION, curl_version());
281 progname, NP_VERSION, VERSION, curl_version());
282 276
283 /* parse arguments */ 277 /* parse arguments */
284 if (process_arguments (argc, argv) == false) 278 if (process_arguments(argc, argv) == false)
285 usage4 (_("Could not parse arguments")); 279 usage4(_("Could not parse arguments"));
286 280
287 if (display_html) 281 if (display_html)
288 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 282 printf("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", use_ssl ? "https" : "http", host_name ? host_name : server_address,
289 use_ssl ? "https" : "http", 283 virtual_port ? virtual_port : server_port, server_url);
290 host_name ? host_name : server_address,
291 virtual_port ? virtual_port : server_port,
292 server_url);
293 284
294 result = check_http (); 285 result = check_http();
295 return result; 286 return result;
296} 287}
297 288
298#ifdef HAVE_SSL 289#ifdef HAVE_SSL
299#ifdef USE_OPENSSL 290# ifdef USE_OPENSSL
300 291
301int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) 292int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) {
302{ 293 (void)preverify_ok;
303 (void) preverify_ok; 294 /* TODO: we get all certificates of the chain, so which ones
304 /* TODO: we get all certificates of the chain, so which ones 295 * should we test?
305 * should we test? 296 * TODO: is the last certificate always the server certificate?
306 * TODO: is the last certificate always the server certificate? 297 */
307 */ 298 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
308 cert = X509_STORE_CTX_get_current_cert(x509_ctx); 299# if OPENSSL_VERSION_NUMBER >= 0x10100000L
309#if OPENSSL_VERSION_NUMBER >= 0x10100000L 300 X509_up_ref(cert);
310 X509_up_ref(cert); 301# endif
311#endif 302 if (verbose >= 2) {
312 if (verbose>=2) { 303 puts("* SSL verify callback with certificate:");
313 puts("* SSL verify callback with certificate:"); 304 X509_NAME *subject;
314 X509_NAME *subject, *issuer; 305 X509_NAME *issuer;
315 printf("* issuer:\n"); 306 printf("* issuer:\n");
316 issuer = X509_get_issuer_name( cert ); 307 issuer = X509_get_issuer_name(cert);
317 X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE); 308 X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE);
318 printf("* curl verify_callback:\n* subject:\n"); 309 printf("* curl verify_callback:\n* subject:\n");
319 subject = X509_get_subject_name( cert ); 310 subject = X509_get_subject_name(cert);
320 X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE); 311 X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE);
321 puts(""); 312 puts("");
322 } 313 }
323 return 1; 314 return 1;
324} 315}
325 316
326CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) 317CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) {
327{ 318 (void)curl; // ignore unused parameter
328 (void) curl; // ignore unused parameter 319 (void)parm; // ignore unused parameter
329 (void) parm; // ignore unused parameter 320 if (add_sslctx_verify_fun) {
330 if(add_sslctx_verify_fun) { 321 SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback);
331 SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback); 322 }
332 } 323
333 324 // workaround for issue:
334 // workaround for issue: 325 // OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0
335 // OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0 326 // see discussion https://github.com/openssl/openssl/discussions/22690
336 // see discussion https://github.com/openssl/openssl/discussions/22690 327# ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
337#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF 328 SSL_CTX_set_options(sslctx, SSL_OP_IGNORE_UNEXPECTED_EOF);
338 SSL_CTX_set_options(sslctx, SSL_OP_IGNORE_UNEXPECTED_EOF); 329# endif
339#endif
340 330
341 return CURLE_OK; 331 return CURLE_OK;
342} 332}
343 333
344#endif /* USE_OPENSSL */ 334# endif /* USE_OPENSSL */
345#endif /* HAVE_SSL */ 335#endif /* HAVE_SSL */
346 336
347/* returns a string "HTTP/1.x" or "HTTP/2" */ 337/* returns a string "HTTP/1.x" or "HTTP/2" */
348static char *string_statuscode (int major, int minor) 338static char *string_statuscode(int major, int minor) {
349{ 339 static char buf[10];
350 static char buf[10]; 340
351 341 switch (major) {
352 switch (major) { 342 case 1:
353 case 1: 343 snprintf(buf, sizeof(buf), "HTTP/%d.%d", major, minor);
354 snprintf (buf, sizeof (buf), "HTTP/%d.%d", major, minor); 344 break;
355 break; 345 case 2:
356 case 2: 346 case 3:
357 case 3: 347 snprintf(buf, sizeof(buf), "HTTP/%d", major);
358 snprintf (buf, sizeof (buf), "HTTP/%d", major); 348 break;
359 break; 349 default:
360 default: 350 /* assuming here HTTP/N with N>=4 */
361 /* assuming here HTTP/N with N>=4 */ 351 snprintf(buf, sizeof(buf), "HTTP/%d", major);
362 snprintf (buf, sizeof (buf), "HTTP/%d", major); 352 break;
363 break; 353 }
364 } 354
365 355 return buf;
366 return buf;
367} 356}
368 357
369/* Checks if the server 'reply' is one of the expected 'statuscodes' */ 358/* Checks if the server 'reply' is one of the expected 'statuscodes' */
370static int 359static int expected_statuscode(const char *reply, const char *statuscodes) {
371expected_statuscode (const char *reply, const char *statuscodes) 360 char *expected;
372{ 361 char *code;
373 char *expected, *code; 362 int result = 0;
374 int result = 0; 363
375 364 if ((expected = strdup(statuscodes)) == NULL)
376 if ((expected = strdup (statuscodes)) == NULL) 365 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
377 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); 366
378 367 for (code = strtok(expected, ","); code != NULL; code = strtok(NULL, ","))
379 for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ",")) 368 if (strstr(reply, code) != NULL) {
380 if (strstr (reply, code) != NULL) { 369 result = 1;
381 result = 1; 370 break;
382 break; 371 }
383 } 372
384 373 free(expected);
385 free (expected); 374 return result;
386 return result;
387} 375}
388 376
389void 377void handle_curl_option_return_code(CURLcode res, const char *option) {
390handle_curl_option_return_code (CURLcode res, const char* option) 378 if (res != CURLE_OK) {
391{ 379 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Error while setting cURL option '%s': cURL returned %d - %s"), option, res,
392 if (res != CURLE_OK) { 380 curl_easy_strerror(res));
393 snprintf (msg, 381 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
394 DEFAULT_BUFFER_SIZE, 382 }
395 _("Error while setting cURL option '%s': cURL returned %d - %s"),
396 option,
397 res,
398 curl_easy_strerror(res));
399 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
400 }
401} 383}
402 384
403int 385int lookup_host(const char *host, char *buf, size_t buflen) {
404lookup_host (const char *host, char *buf, size_t buflen) 386 struct addrinfo hints, *res, *result;
405{ 387 char addrstr[100];
406 struct addrinfo hints, *res, *result; 388 size_t addrstr_len;
407 char addrstr[100]; 389 int errcode;
408 size_t addrstr_len; 390 void *ptr = {0};
409 int errcode; 391 size_t buflen_remaining = buflen - 1;
410 void *ptr = { 0 }; 392
411 size_t buflen_remaining = buflen - 1; 393 memset(&hints, 0, sizeof(hints));
412 394 hints.ai_family = address_family;
413 memset (&hints, 0, sizeof (hints)); 395 hints.ai_socktype = SOCK_STREAM;
414 hints.ai_family = address_family; 396 hints.ai_flags |= AI_CANONNAME;
415 hints.ai_socktype = SOCK_STREAM; 397
416 hints.ai_flags |= AI_CANONNAME; 398 errcode = getaddrinfo(host, NULL, &hints, &result);
417 399 if (errcode != 0)
418 errcode = getaddrinfo (host, NULL, &hints, &result); 400 return errcode;
419 if (errcode != 0) 401
420 return errcode; 402 strcpy(buf, "");
421 403 res = result;
422 strcpy(buf, ""); 404
423 res = result; 405 while (res) {
424 406 switch (res->ai_family) {
425 while (res) { 407 case AF_INET:
426 switch (res->ai_family) { 408 ptr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
427 case AF_INET: 409 break;
428 ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr; 410 case AF_INET6:
429 break; 411 ptr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
430 case AF_INET6: 412 break;
431 ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; 413 }
432 break; 414
433 } 415 inet_ntop(res->ai_family, ptr, addrstr, 100);
434 416 if (verbose >= 1) {
435 inet_ntop (res->ai_family, ptr, addrstr, 100); 417 printf("* getaddrinfo IPv%d address: %s\n", res->ai_family == PF_INET6 ? 6 : 4, addrstr);
436 if (verbose >= 1) { 418 }
437 printf ("* getaddrinfo IPv%d address: %s\n", 419
438 res->ai_family == PF_INET6 ? 6 : 4, addrstr); 420 // Append all IPs to buf as a comma-separated string
439 } 421 addrstr_len = strlen(addrstr);
440 422 if (buflen_remaining > addrstr_len + 1) {
441 // Append all IPs to buf as a comma-separated string 423 if (buf[0] != '\0') {
442 addrstr_len = strlen(addrstr); 424 strncat(buf, ",", buflen_remaining);
443 if (buflen_remaining > addrstr_len + 1) { 425 buflen_remaining -= 1;
444 if (buf[0] != '\0') { 426 }
445 strncat(buf, ",", buflen_remaining); 427 strncat(buf, addrstr, buflen_remaining);
446 buflen_remaining -= 1; 428 buflen_remaining -= addrstr_len;
447 } 429 }
448 strncat(buf, addrstr, buflen_remaining); 430
449 buflen_remaining -= addrstr_len; 431 res = res->ai_next;
450 } 432 }
451 433
452 res = res->ai_next; 434 freeaddrinfo(result);
453 } 435
454 436 return 0;
455 freeaddrinfo(result);
456
457 return 0;
458} 437}
459 438
460static void 439static void cleanup(void) {
461cleanup (void) 440 if (status_line_initialized)
462{ 441 curlhelp_free_statusline(&status_line);
463 if (status_line_initialized) curlhelp_free_statusline(&status_line); 442 status_line_initialized = false;
464 status_line_initialized = false; 443 if (curl_easy_initialized)
465 if (curl_easy_initialized) curl_easy_cleanup (curl); 444 curl_easy_cleanup(curl);
466 curl_easy_initialized = false; 445 curl_easy_initialized = false;
467 if (curl_global_initialized) curl_global_cleanup (); 446 if (curl_global_initialized)
468 curl_global_initialized = false; 447 curl_global_cleanup();
469 if (body_buf_initialized) curlhelp_freewritebuffer (&body_buf); 448 curl_global_initialized = false;
470 body_buf_initialized = false; 449 if (body_buf_initialized)
471 if (header_buf_initialized) curlhelp_freewritebuffer (&header_buf); 450 curlhelp_freewritebuffer(&body_buf);
472 header_buf_initialized = false; 451 body_buf_initialized = false;
473 if (put_buf_initialized) curlhelp_freereadbuffer (&put_buf); 452 if (header_buf_initialized)
474 put_buf_initialized = false; 453 curlhelp_freewritebuffer(&header_buf);
454 header_buf_initialized = false;
455 if (put_buf_initialized)
456 curlhelp_freereadbuffer(&put_buf);
457 put_buf_initialized = false;
475} 458}
476 459
477int 460int check_http(void) {
478check_http (void) 461 int result = STATE_OK;
479{ 462 int result_ssl = STATE_OK;
480 int result = STATE_OK; 463 int page_len = 0;
481 int result_ssl = STATE_OK; 464 int i;
482 int page_len = 0; 465 char *force_host_header = NULL;
483 int i; 466 struct curl_slist *host = NULL;
484 char *force_host_header = NULL; 467 char addrstr[DEFAULT_BUFFER_SIZE / 2];
485 struct curl_slist *host = NULL; 468 char dnscache[DEFAULT_BUFFER_SIZE];
486 char addrstr[DEFAULT_BUFFER_SIZE/2]; 469
487 char dnscache[DEFAULT_BUFFER_SIZE]; 470 /* initialize curl */
488 471 if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK)
489 /* initialize curl */ 472 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
490 if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK) 473 curl_global_initialized = true;
491 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n"); 474
492 curl_global_initialized = true; 475 if ((curl = curl_easy_init()) == NULL) {
493 476 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n");
494 if ((curl = curl_easy_init()) == NULL) { 477 }
495 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n"); 478 curl_easy_initialized = true;
496 } 479
497 curl_easy_initialized = true; 480 /* register cleanup function to shut down libcurl properly */
498 481 atexit(cleanup);
499 /* register cleanup function to shut down libcurl properly */ 482
500 atexit (cleanup); 483 if (verbose >= 1)
501 484 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE");
502 if (verbose >= 1) 485
503 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE"); 486 /* print everything on stdout like check_http would do */
504 487 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR");
505 /* print everything on stdout like check_http would do */ 488
506 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR"); 489 if (automatic_decompression)
507
508 if (automatic_decompression)
509#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) 490#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6)
510 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), "CURLOPT_ACCEPT_ENCODING"); 491 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), "CURLOPT_ACCEPT_ENCODING");
511#else 492#else
512 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING"); 493 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING");
513#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */ 494#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */
514 495
515 /* initialize buffer for body of the answer */ 496 /* initialize buffer for body of the answer */
516 if (curlhelp_initwritebuffer(&body_buf) < 0) 497 if (curlhelp_initwritebuffer(&body_buf) < 0)
517 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); 498 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
518 body_buf_initialized = true; 499 body_buf_initialized = true;
519 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_WRITEFUNCTION"); 500 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback),
520 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA"); 501 "CURLOPT_WRITEFUNCTION");
521 502 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA");
522 /* initialize buffer for header of the answer */ 503
523 if (curlhelp_initwritebuffer( &header_buf ) < 0) 504 /* initialize buffer for header of the answer */
524 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n" ); 505 if (curlhelp_initwritebuffer(&header_buf) < 0)
525 header_buf_initialized = true; 506 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n");
526 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_HEADERFUNCTION"); 507 header_buf_initialized = true;
527 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEHEADER, (void *)&header_buf), "CURLOPT_WRITEHEADER"); 508 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback),
528 509 "CURLOPT_HEADERFUNCTION");
529 /* set the error buffer */ 510 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *)&header_buf), "CURLOPT_WRITEHEADER");
530 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER"); 511
531 512 /* set the error buffer */
532 /* set timeouts */ 513 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER");
533 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, socket_timeout), "CURLOPT_CONNECTTIMEOUT"); 514
534 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_TIMEOUT, socket_timeout), "CURLOPT_TIMEOUT"); 515 /* set timeouts */
535 516 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, socket_timeout), "CURLOPT_CONNECTTIMEOUT");
536 /* enable haproxy protocol */ 517 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_TIMEOUT, socket_timeout), "CURLOPT_TIMEOUT");
537 if (haproxy_protocol) { 518
538 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L), "CURLOPT_HAPROXYPROTOCOL"); 519 /* enable haproxy protocol */
539 } 520 if (haproxy_protocol) {
540 521 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L), "CURLOPT_HAPROXYPROTOCOL");
541 // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we use the host_name later on to make SNI happy 522 }
542 if(use_ssl && host_name != NULL) { 523
543 if ( (res=lookup_host (server_address, addrstr, DEFAULT_BUFFER_SIZE/2)) != 0) { 524 // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we
544 snprintf (msg, 525 // use the host_name later on to make SNI happy
545 DEFAULT_BUFFER_SIZE, 526 if (use_ssl && host_name != NULL) {
546 _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), 527 if ((res = lookup_host(server_address, addrstr, DEFAULT_BUFFER_SIZE / 2)) != 0) {
547 server_address, 528 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %d"), server_address, res,
548 res, 529 gai_strerror(res));
549 gai_strerror (res)); 530 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
550 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 531 }
551 } 532 snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr);
552 snprintf (dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr); 533 host = curl_slist_append(NULL, dnscache);
553 host = curl_slist_append(NULL, dnscache); 534 curl_easy_setopt(curl, CURLOPT_RESOLVE, host);
554 curl_easy_setopt(curl, CURLOPT_RESOLVE, host); 535 if (verbose >= 1)
555 if (verbose>=1) 536 printf("* curl CURLOPT_RESOLVE: %s\n", dnscache);
556 printf ("* curl CURLOPT_RESOLVE: %s\n", dnscache); 537 }
557 } 538
558 539 // If server_address is an IPv6 address it must be surround by square brackets
559 // If server_address is an IPv6 address it must be surround by square brackets 540 struct in6_addr tmp_in_addr;
560 struct in6_addr tmp_in_addr; 541 if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) {
561 if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) { 542 char *new_server_address = malloc(strlen(server_address) + 3);
562 char *new_server_address = malloc(strlen(server_address) + 3); 543 if (new_server_address == NULL) {
563 if (new_server_address == NULL) { 544 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
564 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n"); 545 }
565 } 546 snprintf(new_server_address, strlen(server_address) + 3, "[%s]", server_address);
566 snprintf(new_server_address, strlen(server_address)+3, "[%s]", server_address); 547 free(server_address);
567 free(server_address); 548 server_address = new_server_address;
568 server_address = new_server_address; 549 }
569 } 550
570 551 /* compose URL: use the address we want to connect to, set Host: header later */
571 /* compose URL: use the address we want to connect to, set Host: header later */ 552 snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", use_ssl ? "https" : "http",
572 snprintf (url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", 553 (use_ssl & (host_name != NULL)) ? host_name : server_address, server_port, server_url);
573 use_ssl ? "https" : "http", 554
574 ( use_ssl & ( host_name != NULL ) ) ? host_name : server_address, 555 if (verbose >= 1)
575 server_port, 556 printf("* curl CURLOPT_URL: %s\n", url);
576 server_url 557 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, url), "CURLOPT_URL");
577 ); 558
578 559 /* extract proxy information for legacy proxy https requests */
579 if (verbose>=1) 560 if (!strcmp(http_method, "CONNECT") || strstr(server_url, "http") == server_url) {
580 printf ("* curl CURLOPT_URL: %s\n", url); 561 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXY, server_address), "CURLOPT_PROXY");
581 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_URL, url), "CURLOPT_URL"); 562 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYPORT, (long)server_port), "CURLOPT_PROXYPORT");
582 563 if (verbose >= 2)
583 /* extract proxy information for legacy proxy https requests */ 564 printf("* curl CURLOPT_PROXY: %s:%d\n", server_address, server_port);
584 if (!strcmp(http_method, "CONNECT") || strstr(server_url, "http") == server_url) { 565 http_method = "GET";
585 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXY, server_address), "CURLOPT_PROXY"); 566 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, server_url), "CURLOPT_URL");
586 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXYPORT, (long)server_port), "CURLOPT_PROXYPORT"); 567 }
587 if (verbose>=2) 568
588 printf ("* curl CURLOPT_PROXY: %s:%d\n", server_address, server_port); 569 /* disable body for HEAD request */
589 http_method = "GET"; 570 if (http_method && !strcmp(http_method, "HEAD")) {
590 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_URL, server_url), "CURLOPT_URL"); 571 no_body = true;
591 } 572 }
592 573
593 /* disable body for HEAD request */ 574 /* set HTTP protocol version */
594 if (http_method && !strcmp (http_method, "HEAD" )) { 575 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, curl_http_version), "CURLOPT_HTTP_VERSION");
595 no_body = true; 576
596 } 577 /* set HTTP method */
597 578 if (http_method) {
598 /* set HTTP protocol version */ 579 if (!strcmp(http_method, "POST"))
599 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HTTP_VERSION, curl_http_version), "CURLOPT_HTTP_VERSION"); 580 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POST, 1), "CURLOPT_POST");
600 581 else if (!strcmp(http_method, "PUT"))
601 /* set HTTP method */ 582 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD");
602 if (http_method) { 583 else
603 if (!strcmp(http_method, "POST")) 584 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, http_method), "CURLOPT_CUSTOMREQUEST");
604 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_POST, 1), "CURLOPT_POST"); 585 }
605 else if (!strcmp(http_method, "PUT")) 586
606 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD"); 587 /* check if Host header is explicitly set in options */
607 else 588 if (http_opt_headers_count) {
608 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST, http_method), "CURLOPT_CUSTOMREQUEST"); 589 for (i = 0; i < http_opt_headers_count; i++) {
609 } 590 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) {
610 591 force_host_header = http_opt_headers[i];
611 /* check if Host header is explicitly set in options */ 592 }
612 if (http_opt_headers_count) { 593 }
613 for (i = 0; i < http_opt_headers_count ; i++) { 594 }
614 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) { 595
615 force_host_header = http_opt_headers[i]; 596 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in anyway */
616 } 597 if (host_name != NULL && force_host_header == NULL) {
617 } 598 if ((virtual_port != HTTP_PORT && !use_ssl) || (virtual_port != HTTPS_PORT && use_ssl)) {
618 } 599 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", host_name, virtual_port);
619 600 } else {
620 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in anyway */ 601 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name);
621 if(host_name != NULL && force_host_header == NULL) { 602 }
622 if((virtual_port != HTTP_PORT && !use_ssl) || (virtual_port != HTTPS_PORT && use_ssl)) { 603 header_list = curl_slist_append(header_list, http_header);
623 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", host_name, virtual_port); 604 }
624 } else { 605
625 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name); 606 /* always close connection, be nice to servers */
626 } 607 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Connection: close");
627 header_list = curl_slist_append (header_list, http_header); 608 header_list = curl_slist_append(header_list, http_header);
628 } 609
629 610 /* attach additional headers supplied by the user */
630 /* always close connection, be nice to servers */ 611 /* optionally send any other header tag */
631 snprintf (http_header, DEFAULT_BUFFER_SIZE, "Connection: close"); 612 if (http_opt_headers_count) {
632 header_list = curl_slist_append (header_list, http_header); 613 for (i = 0; i < http_opt_headers_count; i++) {
633 614 header_list = curl_slist_append(header_list, http_opt_headers[i]);
634 /* attach additional headers supplied by the user */ 615 }
635 /* optionally send any other header tag */ 616 /* This cannot be free'd here because a redirection will then try to access this and segfault */
636 if (http_opt_headers_count) { 617 /* Covered in a testcase in tests/check_http.t */
637 for (i = 0; i < http_opt_headers_count ; i++) { 618 /* free(http_opt_headers); */
638 header_list = curl_slist_append (header_list, http_opt_headers[i]); 619 }
639 } 620
640 /* This cannot be free'd here because a redirection will then try to access this and segfault */ 621 /* set HTTP headers */
641 /* Covered in a testcase in tests/check_http.t */ 622 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list), "CURLOPT_HTTPHEADER");
642 /* free(http_opt_headers); */
643 }
644
645 /* set HTTP headers */
646 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list ), "CURLOPT_HTTPHEADER");
647 623
648#ifdef LIBCURL_FEATURE_SSL 624#ifdef LIBCURL_FEATURE_SSL
649 625
650 /* set SSL version, warn about insecure or unsupported versions */ 626 /* set SSL version, warn about insecure or unsupported versions */
651 if (use_ssl) { 627 if (use_ssl) {
652 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION"); 628 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION");
653 } 629 }
654 630
655 /* client certificate and key to present to server (SSL) */ 631 /* client certificate and key to present to server (SSL) */
656 if (client_cert) 632 if (client_cert)
657 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLCERT, client_cert), "CURLOPT_SSLCERT"); 633 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert), "CURLOPT_SSLCERT");
658 if (client_privkey) 634 if (client_privkey)
659 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLKEY, client_privkey), "CURLOPT_SSLKEY"); 635 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLKEY, client_privkey), "CURLOPT_SSLKEY");
660 if (ca_cert) { 636 if (ca_cert) {
661 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO"); 637 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO");
662 } 638 }
663 if (ca_cert || verify_peer_and_host) { 639 if (ca_cert || verify_peer_and_host) {
664 /* per default if we have a CA verify both the peer and the 640 /* per default if we have a CA verify both the peer and the
665 * hostname in the certificate, can be switched off later */ 641 * hostname in the certificate, can be switched off later */
666 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 1), "CURLOPT_SSL_VERIFYPEER"); 642 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1), "CURLOPT_SSL_VERIFYPEER");
667 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST"); 643 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST");
668 } else { 644 } else {
669 /* backward-compatible behaviour, be tolerant in checks 645 /* backward-compatible behaviour, be tolerant in checks
670 * TODO: depending on more options have aspects we want 646 * TODO: depending on more options have aspects we want
671 * to be less tolerant about ssl verfications 647 * to be less tolerant about ssl verfications
672 */ 648 */
673 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER"); 649 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER");
674 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST"); 650 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST");
675 } 651 }
676 652
677 /* detect SSL library used by libcurl */ 653 /* detect SSL library used by libcurl */
678 ssl_library = curlhelp_get_ssl_library (); 654 ssl_library = curlhelp_get_ssl_library();
679 655
680 /* try hard to get a stack of certificates to verify against */ 656 /* try hard to get a stack of certificates to verify against */
681 if (check_cert) { 657 if (check_cert) {
682#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) 658# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
683 /* inform curl to report back certificates */ 659 /* inform curl to report back certificates */
684 switch (ssl_library) { 660 switch (ssl_library) {
685 case CURLHELP_SSL_LIBRARY_OPENSSL: 661 case CURLHELP_SSL_LIBRARY_OPENSSL:
686 case CURLHELP_SSL_LIBRARY_LIBRESSL: 662 case CURLHELP_SSL_LIBRARY_LIBRESSL:
687 /* set callback to extract certificate with OpenSSL context function (works with 663 /* set callback to extract certificate with OpenSSL context function (works with
688 * OpenSSL-style libraries only!) */ 664 * OpenSSL-style libraries only!) */
689#ifdef USE_OPENSSL 665# ifdef USE_OPENSSL
690 /* libcurl and monitoring plugins built with OpenSSL, good */ 666 /* libcurl and monitoring plugins built with OpenSSL, good */
691 add_sslctx_verify_fun = true; 667 add_sslctx_verify_fun = true;
692 is_openssl_callback = true; 668 is_openssl_callback = true;
693#endif /* USE_OPENSSL */ 669# endif /* USE_OPENSSL */
694 /* libcurl is built with OpenSSL, monitoring plugins, so falling 670 /* libcurl is built with OpenSSL, monitoring plugins, so falling
695 * back to manually extracting certificate information */ 671 * back to manually extracting certificate information */
696 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); 672 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
697 break; 673 break;
698 674
699 case CURLHELP_SSL_LIBRARY_NSS: 675 case CURLHELP_SSL_LIBRARY_NSS:
700#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 676# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
701 /* NSS: support for CERTINFO is implemented since 7.34.0 */ 677 /* NSS: support for CERTINFO is implemented since 7.34.0 */
702 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); 678 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
703#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 679# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
704 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", curlhelp_get_ssl_library_string (ssl_library)); 680 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n",
705#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 681 curlhelp_get_ssl_library_string(ssl_library));
706 break; 682# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
707 683 break;
708 case CURLHELP_SSL_LIBRARY_GNUTLS: 684
709#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) 685 case CURLHELP_SSL_LIBRARY_GNUTLS:
710 /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */ 686# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
711 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); 687 /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */
712#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */ 688 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
713 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", curlhelp_get_ssl_library_string (ssl_library)); 689# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
714#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */ 690 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n",
715 break; 691 curlhelp_get_ssl_library_string(ssl_library));
716 692# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
717 case CURLHELP_SSL_LIBRARY_UNKNOWN: 693 break;
718 default: 694
719 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must implement first)\n", curlhelp_get_ssl_library_string (ssl_library)); 695 case CURLHELP_SSL_LIBRARY_UNKNOWN:
720 break; 696 default:
721 } 697 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must implement first)\n",
722#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ 698 curlhelp_get_ssl_library_string(ssl_library));
723 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */ 699 break;
724 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL || ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL) 700 }
725 add_sslctx_verify_fun = true; 701# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
726 else 702 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */
727 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl too old and has no CURLOPT_CERTINFO)\n"); 703 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL || ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL)
728#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ 704 add_sslctx_verify_fun = true;
729 } 705 else
730 706 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl "
731#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */ 707 "too old and has no CURLOPT_CERTINFO)\n");
732 // ssl ctx function is not available with all ssl backends 708# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
733 if (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, NULL) != CURLE_UNKNOWN_OPTION) 709 }
734 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); 710
735#endif 711# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */
712 // ssl ctx function is not available with all ssl backends
713 if (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, NULL) != CURLE_UNKNOWN_OPTION)
714 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
715# endif
736 716
737#endif /* LIBCURL_FEATURE_SSL */ 717#endif /* LIBCURL_FEATURE_SSL */
738 718
739 /* set default or user-given user agent identification */ 719 /* set default or user-given user agent identification */
740 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT"); 720 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT");
741 721
742 /* proxy-authentication */ 722 /* proxy-authentication */
743 if (strcmp(proxy_auth, "")) 723 if (strcmp(proxy_auth, ""))
744 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXYUSERPWD, proxy_auth), "CURLOPT_PROXYUSERPWD"); 724 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_auth), "CURLOPT_PROXYUSERPWD");
745 725
746 /* authentication */ 726 /* authentication */
747 if (strcmp(user_auth, "")) 727 if (strcmp(user_auth, ""))
748 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERPWD, user_auth), "CURLOPT_USERPWD"); 728 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERPWD, user_auth), "CURLOPT_USERPWD");
749 729
750 /* TODO: parameter auth method, bitfield of following methods: 730 /* TODO: parameter auth method, bitfield of following methods:
751 * CURLAUTH_BASIC (default) 731 * CURLAUTH_BASIC (default)
752 * CURLAUTH_DIGEST 732 * CURLAUTH_DIGEST
753 * CURLAUTH_DIGEST_IE 733 * CURLAUTH_DIGEST_IE
754 * CURLAUTH_NEGOTIATE 734 * CURLAUTH_NEGOTIATE
755 * CURLAUTH_NTLM 735 * CURLAUTH_NTLM
756 * CURLAUTH_NTLM_WB 736 * CURLAUTH_NTLM_WB
757 * 737 *
758 * convenience tokens for typical sets of methods: 738 * convenience tokens for typical sets of methods:
759 * CURLAUTH_ANYSAFE: most secure, without BASIC 739 * CURLAUTH_ANYSAFE: most secure, without BASIC
760 * or CURLAUTH_ANY: most secure, even BASIC if necessary 740 * or CURLAUTH_ANY: most secure, even BASIC if necessary
761 * 741 *
762 * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH"); 742 * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH");
763 */ 743 */
764 744
765 /* handle redirections */ 745 /* handle redirections */
766 if (onredirect == STATE_DEPENDENT) { 746 if (onredirect == STATE_DEPENDENT) {
767 if( followmethod == FOLLOW_LIBCURL ) { 747 if (followmethod == FOLLOW_LIBCURL) {
768 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION"); 748 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION");
769 749
770 /* default -1 is infinite, not good, could lead to zombie plugins! 750 /* default -1 is infinite, not good, could lead to zombie plugins!
771 Setting it to one bigger than maximal limit to handle errors nicely below 751 Setting it to one bigger than maximal limit to handle errors nicely below
772 */ 752 */
773 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_MAXREDIRS, max_depth+1), "CURLOPT_MAXREDIRS"); 753 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_MAXREDIRS, max_depth + 1), "CURLOPT_MAXREDIRS");
774 754
775 /* for now allow only http and https (we are a http(s) check plugin in the end) */ 755 /* for now allow only http and https (we are a http(s) check plugin in the end) */
776#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0) 756#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0)
777 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"), "CURLOPT_REDIR_PROTOCOLS_STR"); 757 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"),
758 "CURLOPT_REDIR_PROTOCOLS_STR");
778#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4) 759#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4)
779 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS), "CURLOPT_REDIRECT_PROTOCOLS"); 760 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS),
761 "CURLOPT_REDIRECT_PROTOCOLS");
780#endif 762#endif
781 763
782 /* TODO: handle the following aspects of redirection, make them 764 /* TODO: handle the following aspects of redirection, make them
783 * command line options too later: 765 * command line options too later:
784 CURLOPT_POSTREDIR: method switch 766 CURLOPT_POSTREDIR: method switch
785 CURLINFO_REDIRECT_URL: custom redirect option 767 CURLINFO_REDIRECT_URL: custom redirect option
786 CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols 768 CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols
787 CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range option here is nice like for expected page size? 769 CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range option here is nice like for expected page size?
788 */ 770 */
789 } else { 771 } else {
790 /* old style redirection is handled below */ 772 /* old style redirection is handled below */
791 } 773 }
792 } 774 }
793 775
794 /* no-body */ 776 /* no-body */
795 if (no_body) 777 if (no_body)
796 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY"); 778 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY");
797 779
798 /* IPv4 or IPv6 forced DNS resolution */ 780 /* IPv4 or IPv6 forced DNS resolution */
799 if (address_family == AF_UNSPEC) 781 if (address_family == AF_UNSPEC)
800 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)"); 782 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER),
801 else if (address_family == AF_INET) 783 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)");
802 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)"); 784 else if (address_family == AF_INET)
803#if defined (USE_IPV6) && defined (LIBCURL_FEATURE_IPV6) 785 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4),
804 else if (address_family == AF_INET6) 786 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)");
805 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)"); 787#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
788 else if (address_family == AF_INET6)
789 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6),
790 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)");
806#endif 791#endif
807 792
808 /* either send http POST data (any data, not only POST)*/ 793 /* either send http POST data (any data, not only POST)*/
809 if (!strcmp(http_method, "POST") ||!strcmp(http_method, "PUT")) { 794 if (!strcmp(http_method, "POST") || !strcmp(http_method, "PUT")) {
810 /* set content of payload for POST and PUT */ 795 /* set content of payload for POST and PUT */
811 if (http_content_type) { 796 if (http_content_type) {
812 snprintf (http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", http_content_type); 797 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", http_content_type);
813 header_list = curl_slist_append (header_list, http_header); 798 header_list = curl_slist_append(header_list, http_header);
814 } 799 }
815 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string 800 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string
816 * in case of no POST/PUT data */ 801 * in case of no POST/PUT data */
817 if (!http_post_data) 802 if (!http_post_data)
818 http_post_data = ""; 803 http_post_data = "";
819 if (!strcmp(http_method, "POST")) { 804 if (!strcmp(http_method, "POST")) {
820 /* POST method, set payload with CURLOPT_POSTFIELDS */ 805 /* POST method, set payload with CURLOPT_POSTFIELDS */
821 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_POSTFIELDS, http_post_data), "CURLOPT_POSTFIELDS"); 806 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POSTFIELDS, http_post_data), "CURLOPT_POSTFIELDS");
822 } else if (!strcmp(http_method, "PUT")) { 807 } else if (!strcmp(http_method, "PUT")) {
823 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback), "CURLOPT_READFUNCTION"); 808 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback),
824 if (curlhelp_initreadbuffer (&put_buf, http_post_data, strlen (http_post_data)) < 0) 809 "CURLOPT_READFUNCTION");
825 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n"); 810 if (curlhelp_initreadbuffer(&put_buf, http_post_data, strlen(http_post_data)) < 0)
826 put_buf_initialized = true; 811 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n");
827 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA"); 812 put_buf_initialized = true;
828 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_INFILESIZE, (curl_off_t)strlen (http_post_data)), "CURLOPT_INFILESIZE"); 813 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA");
829 } 814 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_INFILESIZE, (curl_off_t)strlen(http_post_data)),
830 } 815 "CURLOPT_INFILESIZE");
831 816 }
832 /* cookie handling */ 817 }
833 if (cookie_jar_file != NULL) { 818
834 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR"); 819 /* cookie handling */
835 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE"); 820 if (cookie_jar_file != NULL) {
836 } 821 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR");
837 822 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE");
838 /* do the request */ 823 }
839 res = curl_easy_perform(curl); 824
840 825 /* do the request */
841 if (verbose>=2 && http_post_data) 826 res = curl_easy_perform(curl);
842 printf ("**** REQUEST CONTENT ****\n%s\n", http_post_data); 827
843 828 if (verbose >= 2 && http_post_data)
844 /* free header and server IP resolve lists, we don't need it anymore */ 829 printf("**** REQUEST CONTENT ****\n%s\n", http_post_data);
845 curl_slist_free_all (header_list); header_list = NULL; 830
846 curl_slist_free_all (server_ips); server_ips = NULL; 831 /* free header and server IP resolve lists, we don't need it anymore */
847 if (host) { 832 curl_slist_free_all(header_list);
848 curl_slist_free_all (host); host = NULL; 833 header_list = NULL;
849 } 834 curl_slist_free_all(server_ips);
850 835 server_ips = NULL;
851 /* Curl errors, result in critical Nagios state */ 836 if (host) {
852 if (res != CURLE_OK) { 837 curl_slist_free_all(host);
853 snprintf (msg, 838 host = NULL;
854 DEFAULT_BUFFER_SIZE, 839 }
855 _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), 840
856 server_port, 841 /* Curl errors, result in critical Nagios state */
857 res, 842 if (res != CURLE_OK) {
858 errbuf[0] ? errbuf : curl_easy_strerror(res)); 843 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), server_port,
859 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 844 res, errbuf[0] ? errbuf : curl_easy_strerror(res));
860 } 845 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
861 846 }
862 /* certificate checks */ 847
848 /* certificate checks */
863#ifdef LIBCURL_FEATURE_SSL 849#ifdef LIBCURL_FEATURE_SSL
864 if (use_ssl) { 850 if (use_ssl) {
865 if (check_cert) { 851 if (check_cert) {
866 if (is_openssl_callback) { 852 if (is_openssl_callback) {
867#ifdef USE_OPENSSL 853# ifdef USE_OPENSSL
868 /* check certificate with OpenSSL functions, curl has been built against OpenSSL 854 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
869 * and we actually have OpenSSL in the monitoring tools 855 * and we actually have OpenSSL in the monitoring tools
870 */ 856 */
871 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 857 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
872 if (!continue_after_check_cert) { 858 if (!continue_after_check_cert) {
873 return result_ssl; 859 return result_ssl;
874 } 860 }
875#else /* USE_OPENSSL */ 861# else /* USE_OPENSSL */
876 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n"); 862 die(STATE_CRITICAL,
877#endif /* USE_OPENSSL */ 863 "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n");
878 } else { 864# endif /* USE_OPENSSL */
879 int i; 865 } else {
880 struct curl_slist *slist; 866 int i;
881 867 struct curl_slist *slist;
882 cert_ptr.to_info = NULL; 868
883 res = curl_easy_getinfo (curl, CURLINFO_CERTINFO, &cert_ptr.to_info); 869 cert_ptr.to_info = NULL;
884 if (!res && cert_ptr.to_info) { 870 res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
885#ifdef USE_OPENSSL 871 if (!res && cert_ptr.to_info) {
886 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert parsing 872# ifdef USE_OPENSSL
887 * We only check the first certificate and assume it's the one of the server 873 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert parsing
888 */ 874 * We only check the first certificate and assume it's the one of the server
889 const char* raw_cert = NULL; 875 */
890 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) { 876 const char *raw_cert = NULL;
891 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) { 877 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) {
892 if (verbose >= 2) 878 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) {
893 printf ("%d ** %s\n", i, slist->data); 879 if (verbose >= 2)
894 if (strncmp (slist->data, "Cert:", 5) == 0) { 880 printf("%d ** %s\n", i, slist->data);
895 raw_cert = &slist->data[5]; 881 if (strncmp(slist->data, "Cert:", 5) == 0) {
896 goto GOT_FIRST_CERT; 882 raw_cert = &slist->data[5];
897 } 883 goto GOT_FIRST_CERT;
898 } 884 }
899 } 885 }
900GOT_FIRST_CERT: 886 }
901 if (!raw_cert) { 887 GOT_FIRST_CERT:
902 snprintf (msg, 888 if (!raw_cert) {
903 DEFAULT_BUFFER_SIZE, 889 snprintf(msg, DEFAULT_BUFFER_SIZE,
904 _("Cannot retrieve certificates from CERTINFO information - certificate data was empty")); 890 _("Cannot retrieve certificates from CERTINFO information - certificate data was empty"));
905 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 891 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
906 } 892 }
907 BIO* cert_BIO = BIO_new (BIO_s_mem()); 893 BIO *cert_BIO = BIO_new(BIO_s_mem());
908 BIO_write (cert_BIO, raw_cert, strlen(raw_cert)); 894 BIO_write(cert_BIO, raw_cert, strlen(raw_cert));
909 cert = PEM_read_bio_X509 (cert_BIO, NULL, NULL, NULL); 895 cert = PEM_read_bio_X509(cert_BIO, NULL, NULL, NULL);
910 if (!cert) { 896 if (!cert) {
911 snprintf (msg, 897 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Cannot read certificate from CERTINFO information - BIO error"));
912 DEFAULT_BUFFER_SIZE, 898 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
913 _("Cannot read certificate from CERTINFO information - BIO error")); 899 }
914 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 900 BIO_free(cert_BIO);
915 } 901 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
916 BIO_free (cert_BIO); 902 if (!continue_after_check_cert) {
917 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 903 return result_ssl;
918 if (!continue_after_check_cert) { 904 }
919 return result_ssl; 905# else /* USE_OPENSSL */
920 } 906 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal,
921#else /* USE_OPENSSL */ 907 * so we use the libcurl CURLINFO data
922 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal, 908 */
923 * so we use the libcurl CURLINFO data 909 result_ssl = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit);
924 */ 910 if (!continue_after_check_cert) {
925 result_ssl = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit); 911 return result_ssl;
926 if (!continue_after_check_cert) { 912 }
927 return result_ssl; 913# endif /* USE_OPENSSL */
928 } 914 } else {
929#endif /* USE_OPENSSL */ 915 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Cannot retrieve certificates - cURL returned %d - %s"), res,
930 } else { 916 curl_easy_strerror(res));
931 snprintf (msg, 917 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
932 DEFAULT_BUFFER_SIZE, 918 }
933 _("Cannot retrieve certificates - cURL returned %d - %s"), 919 }
934 res, 920 }
935 curl_easy_strerror(res)); 921 }
936 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
937 }
938 }
939 }
940 }
941#endif /* LIBCURL_FEATURE_SSL */ 922#endif /* LIBCURL_FEATURE_SSL */
942 923
943 /* we got the data and we executed the request in a given time, so we can append 924 /* we got the data and we executed the request in a given time, so we can append
944 * performance data to the answer always 925 * performance data to the answer always
945 */ 926 */
946 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_TOTAL_TIME, &total_time), "CURLINFO_TOTAL_TIME"); 927 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time), "CURLINFO_TOTAL_TIME");
947 page_len = get_content_length(&header_buf, &body_buf); 928 page_len = get_content_length(&header_buf, &body_buf);
948 if(show_extended_perfdata) { 929 if (show_extended_perfdata) {
949 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME"); 930 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME");
950 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), "CURLINFO_APPCONNECT_TIME"); 931 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), "CURLINFO_APPCONNECT_TIME");
951 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &time_headers), "CURLINFO_PRETRANSFER_TIME"); 932 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &time_headers), "CURLINFO_PRETRANSFER_TIME");
952 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte), "CURLINFO_STARTTRANSFER_TIME"); 933 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte),
953 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", 934 "CURLINFO_STARTTRANSFER_TIME");
954 perfd_time(total_time), 935 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", perfd_time(total_time), perfd_size(page_len),
955 perfd_size(page_len), 936 perfd_time_connect(time_connect), use_ssl ? perfd_time_ssl(time_appconnect - time_connect) : "",
956 perfd_time_connect(time_connect), 937 perfd_time_headers(time_headers - time_appconnect), perfd_time_firstbyte(time_firstbyte - time_headers),
957 use_ssl ? perfd_time_ssl (time_appconnect-time_connect) : "", 938 perfd_time_transfer(total_time - time_firstbyte));
958 perfd_time_headers(time_headers - time_appconnect), 939 } else {
959 perfd_time_firstbyte(time_firstbyte - time_headers), 940 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s", perfd_time(total_time), perfd_size(page_len));
960 perfd_time_transfer(total_time-time_firstbyte) 941 }
961 );
962 } else {
963 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s",
964 perfd_time(total_time),
965 perfd_size(page_len)
966 );
967 }
968
969 /* return a CRITICAL status if we couldn't read any data */
970 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0)
971 die (STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
972
973 /* get status line of answer, check sanity of HTTP code */
974 if (curlhelp_parse_statusline (header_buf.buf, &status_line) < 0) {
975 snprintf (msg,
976 DEFAULT_BUFFER_SIZE,
977 "Unparsable status line in %.3g seconds response time|%s\n",
978 total_time,
979 perfstring);
980 /* we cannot know the major/minor version here for sure as we cannot parse the first line */
981 die (STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg);
982 }
983 status_line_initialized = true;
984
985 /* get result code from cURL */
986 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE");
987 if (verbose>=2)
988 printf ("* curl CURLINFO_RESPONSE_CODE is %ld\n", code);
989
990 /* print status line, header, body if verbose */
991 if (verbose >= 2) {
992 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf,
993 (no_body ? " [[ skipped ]]" : body_buf.buf));
994 }
995
996 /* make sure the status line matches the response we are looking for */
997 if (!expected_statuscode(status_line.first_line, server_expect)) {
998 if (server_port == HTTP_PORT)
999 snprintf(msg,
1000 DEFAULT_BUFFER_SIZE,
1001 _("Invalid HTTP response received from host: %s\n"),
1002 status_line.first_line);
1003 else
1004 snprintf(msg,
1005 DEFAULT_BUFFER_SIZE,
1006 _("Invalid HTTP response received from host on port %d: %s\n"),
1007 server_port,
1008 status_line.first_line);
1009 die (STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg,
1010 show_body ? "\n" : "",
1011 show_body ? body_buf.buf : "");
1012 }
1013
1014 if( server_expect_yn ) {
1015 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), server_expect);
1016 if (verbose)
1017 printf ("%s\n",msg);
1018 result = STATE_OK;
1019 }
1020 else {
1021 /* illegal return codes result in a critical state */
1022 if (code >= 600 || code < 100) {
1023 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg);
1024 /* server errors result in a critical state */
1025 } else if (code >= 500) {
1026 result = STATE_CRITICAL;
1027 /* client errors result in a warning state */
1028 } else if (code >= 400) {
1029 result = STATE_WARNING;
1030 /* check redirected page if specified */
1031 } else if (code >= 300) {
1032 if (onredirect == STATE_DEPENDENT) {
1033 if( followmethod == FOLLOW_LIBCURL ) {
1034 code = status_line.http_code;
1035 } else {
1036 /* old check_http style redirection, if we come
1037 * back here, we are in the same status as with
1038 * the libcurl method
1039 */
1040 redir (&header_buf);
1041 }
1042 } else {
1043 /* this is a specific code in the command line to
1044 * be returned when a redirection is encountered
1045 */
1046 }
1047 result = max_state_alt (onredirect, result);
1048 /* all other codes are considered ok */
1049 } else {
1050 result = STATE_OK;
1051 }
1052 }
1053
1054 /* libcurl redirection internally, handle error states here */
1055 if( followmethod == FOLLOW_LIBCURL ) {
1056 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT");
1057 if (verbose >= 2)
1058 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth);
1059 if (redir_depth > max_depth) {
1060 snprintf (msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl",
1061 max_depth);
1062 die (STATE_WARNING, "HTTP WARNING - %s", msg);
1063 }
1064 }
1065
1066 /* check status codes, set exit status accordingly */
1067 if( status_line.http_code != code ) {
1068 die (STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"),
1069 string_statuscode (status_line.http_major, status_line.http_minor),
1070 status_line.http_code, status_line.msg, code);
1071 }
1072
1073 if (maximum_age >= 0) {
1074 result = max_state_alt(check_document_dates(&header_buf, &msg), result);
1075 }
1076
1077 /* Page and Header content checks go here */
1078
1079 if (strlen (header_expect)) {
1080 if (!strstr (header_buf.buf, header_expect)) {
1081
1082 strncpy(&output_header_search[0],header_expect,sizeof(output_header_search));
1083
1084 if(output_header_search[sizeof(output_header_search)-1]!='\0') {
1085 bcopy("...",&output_header_search[sizeof(output_header_search)-4],4);
1086 }
1087 942
1088 char tmp[DEFAULT_BUFFER_SIZE]; 943 /* return a CRITICAL status if we couldn't read any data */
944 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0)
945 die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
1089 946
1090 snprintf (tmp, 947 /* get status line of answer, check sanity of HTTP code */
1091 DEFAULT_BUFFER_SIZE, 948 if (curlhelp_parse_statusline(header_buf.buf, &status_line) < 0) {
1092 _("%sheader '%s' not found on '%s://%s:%d%s', "), 949 snprintf(msg, DEFAULT_BUFFER_SIZE, "Unparsable status line in %.3g seconds response time|%s\n", total_time, perfstring);
1093 msg, 950 /* we cannot know the major/minor version here for sure as we cannot parse the first line */
1094 output_header_search, 951 die(STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg);
1095 use_ssl ? "https" : "http", 952 }
1096 host_name ? host_name : server_address, 953 status_line_initialized = true;
1097 server_port,
1098 server_url);
1099 954
1100 strcpy(msg, tmp); 955 /* get result code from cURL */
956 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE");
957 if (verbose >= 2)
958 printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", code);
1101 959
1102 result = STATE_CRITICAL; 960 /* print status line, header, body if verbose */
1103 } 961 if (verbose >= 2) {
1104 } 962 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf, (no_body ? " [[ skipped ]]" : body_buf.buf));
963 }
1105 964
1106 if (strlen (string_expect)) { 965 /* make sure the status line matches the response we are looking for */
1107 if (!strstr (body_buf.buf, string_expect)) { 966 if (!expected_statuscode(status_line.first_line, server_expect)) {
967 if (server_port == HTTP_PORT)
968 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), status_line.first_line);
969 else
970 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: %s\n"), server_port,
971 status_line.first_line);
972 die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, show_body ? "\n" : "", show_body ? body_buf.buf : "");
973 }
1108 974
1109 strncpy(&output_string_search[0],string_expect,sizeof(output_string_search)); 975 if (server_expect_yn) {
976 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), server_expect);
977 if (verbose)
978 printf("%s\n", msg);
979 result = STATE_OK;
980 } else {
981 /* illegal return codes result in a critical state */
982 if (code >= 600 || code < 100) {
983 die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg);
984 /* server errors result in a critical state */
985 } else if (code >= 500) {
986 result = STATE_CRITICAL;
987 /* client errors result in a warning state */
988 } else if (code >= 400) {
989 result = STATE_WARNING;
990 /* check redirected page if specified */
991 } else if (code >= 300) {
992 if (onredirect == STATE_DEPENDENT) {
993 if (followmethod == FOLLOW_LIBCURL) {
994 code = status_line.http_code;
995 } else {
996 /* old check_http style redirection, if we come
997 * back here, we are in the same status as with
998 * the libcurl method
999 */
1000 redir(&header_buf);
1001 }
1002 } else {
1003 /* this is a specific code in the command line to
1004 * be returned when a redirection is encountered
1005 */
1006 }
1007 result = max_state_alt(onredirect, result);
1008 /* all other codes are considered ok */
1009 } else {
1010 result = STATE_OK;
1011 }
1012 }
1110 1013
1111 if(output_string_search[sizeof(output_string_search)-1]!='\0') { 1014 /* libcurl redirection internally, handle error states here */
1112 bcopy("...",&output_string_search[sizeof(output_string_search)-4],4); 1015 if (followmethod == FOLLOW_LIBCURL) {
1113 } 1016 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT");
1017 if (verbose >= 2)
1018 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth);
1019 if (redir_depth > max_depth) {
1020 snprintf(msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl", max_depth);
1021 die(STATE_WARNING, "HTTP WARNING - %s", msg);
1022 }
1023 }
1024
1025 /* check status codes, set exit status accordingly */
1026 if (status_line.http_code != code) {
1027 die(STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"),
1028 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg, code);
1029 }
1030
1031 if (maximum_age >= 0) {
1032 result = max_state_alt(check_document_dates(&header_buf, &msg), result);
1033 }
1034
1035 /* Page and Header content checks go here */
1036
1037 if (strlen(header_expect)) {
1038 if (!strstr(header_buf.buf, header_expect)) {
1039
1040 strncpy(&output_header_search[0], header_expect, sizeof(output_header_search));
1041
1042 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1043 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4);
1044 }
1045
1046 char tmp[DEFAULT_BUFFER_SIZE];
1047
1048 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg, output_header_search,
1049 use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url);
1050
1051 strcpy(msg, tmp);
1052
1053 result = STATE_CRITICAL;
1054 }
1055 }
1056
1057 if (strlen(string_expect)) {
1058 if (!strstr(body_buf.buf, string_expect)) {
1059
1060 strncpy(&output_string_search[0], string_expect, sizeof(output_string_search));
1061
1062 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1063 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4);
1064 }
1114 1065
1115 char tmp[DEFAULT_BUFFER_SIZE]; 1066 char tmp[DEFAULT_BUFFER_SIZE];
1116 1067
1117 snprintf (tmp, 1068 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search,
1118 DEFAULT_BUFFER_SIZE, 1069 use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url);
1119 _("%sstring '%s' not found on '%s://%s:%d%s', "),
1120 msg,
1121 output_string_search,
1122 use_ssl ? "https" : "http",
1123 host_name ? host_name : server_address,
1124 server_port,
1125 server_url);
1126 1070
1127 strcpy(msg, tmp); 1071 strcpy(msg, tmp);
1128 1072
1129 result = STATE_CRITICAL; 1073 result = STATE_CRITICAL;
1130 } 1074 }
1131 } 1075 }
1132 1076
1133 if (strlen (regexp)) { 1077 if (strlen(regexp)) {
1134 errcode = regexec (&preg, body_buf.buf, REGS, pmatch, 0); 1078 errcode = regexec(&preg, body_buf.buf, REGS, pmatch, 0);
1135 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) { 1079 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) {
1136 /* OK - No-op to avoid changing the logic around it */ 1080 /* OK - No-op to avoid changing the logic around it */
1137 result = max_state_alt(STATE_OK, result); 1081 result = max_state_alt(STATE_OK, result);
1138 } 1082 } else if ((errcode == REG_NOMATCH && !invert_regex) || (errcode == 0 && invert_regex)) {
1139 else if ((errcode == REG_NOMATCH && !invert_regex) || (errcode == 0 && invert_regex)) {
1140 if (!invert_regex) { 1083 if (!invert_regex) {
1141 char tmp[DEFAULT_BUFFER_SIZE]; 1084 char tmp[DEFAULT_BUFFER_SIZE];
1142 1085
1143 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg); 1086 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg);
1144 strcpy(msg, tmp); 1087 strcpy(msg, tmp);
1145 1088
1146 } else { 1089 } else {
1147 char tmp[DEFAULT_BUFFER_SIZE]; 1090 char tmp[DEFAULT_BUFFER_SIZE];
1148 1091
1149 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg); 1092 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg);
1150 strcpy(msg, tmp); 1093 strcpy(msg, tmp);
1151
1152 } 1094 }
1153 result = state_regex; 1095 result = state_regex;
1154 } else { 1096 } else {
1155 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1097 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1156 1098
1157 char tmp[DEFAULT_BUFFER_SIZE]; 1099 char tmp[DEFAULT_BUFFER_SIZE];
1158 1100
1159 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf); 1101 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf);
1160 strcpy(msg, tmp); 1102 strcpy(msg, tmp);
1161 result = STATE_UNKNOWN; 1103 result = STATE_UNKNOWN;
1162 } 1104 }
1163 } 1105 }
1164 1106
1165 /* make sure the page is of an appropriate size */ 1107 /* make sure the page is of an appropriate size */
1166 if ((max_page_len > 0) && (page_len > max_page_len)) { 1108 if ((max_page_len > 0) && (page_len > max_page_len)) {
1167 char tmp[DEFAULT_BUFFER_SIZE]; 1109 char tmp[DEFAULT_BUFFER_SIZE];
1168 1110
1169 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len); 1111 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len);
1170 1112
1171 strcpy(msg, tmp); 1113 strcpy(msg, tmp);
1172 1114
@@ -1175,1281 +1117,1230 @@ GOT_FIRST_CERT:
1175 } else if ((min_page_len > 0) && (page_len < min_page_len)) { 1117 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1176 char tmp[DEFAULT_BUFFER_SIZE]; 1118 char tmp[DEFAULT_BUFFER_SIZE];
1177 1119
1178 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len); 1120 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len);
1179 strcpy(msg, tmp); 1121 strcpy(msg, tmp);
1180 result = max_state_alt(STATE_WARNING, result); 1122 result = max_state_alt(STATE_WARNING, result);
1181 } 1123 }
1182 1124
1183 /* -w, -c: check warning and critical level */ 1125 /* -w, -c: check warning and critical level */
1184 result = max_state_alt(get_status(total_time, thlds), result); 1126 result = max_state_alt(get_status(total_time, thlds), result);
1185 1127
1186 /* Cut-off trailing characters */ 1128 /* Cut-off trailing characters */
1187 if (strlen(msg) >= 2) { 1129 if (strlen(msg) >= 2) {
1188 if(msg[strlen(msg)-2] == ',') 1130 if (msg[strlen(msg) - 2] == ',')
1189 msg[strlen(msg)-2] = '\0'; 1131 msg[strlen(msg) - 2] = '\0';
1190 else 1132 else
1191 msg[strlen(msg)-3] = '\0'; 1133 msg[strlen(msg) - 3] = '\0';
1192 } 1134 }
1193 1135
1194 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */ 1136 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */
1195 die (max_state_alt(result, result_ssl), "HTTP %s: %s %d %s%s%s - %d bytes in %.3f second response time %s|%s\n%s%s", 1137 die(max_state_alt(result, result_ssl), "HTTP %s: %s %d %s%s%s - %d bytes in %.3f second response time %s|%s\n%s%s", state_text(result),
1196 state_text(result), string_statuscode (status_line.http_major, status_line.http_minor), 1138 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg,
1197 status_line.http_code, status_line.msg, 1139 strlen(msg) > 0 ? " - " : "", msg, page_len, total_time, (display_html ? "</A>" : ""), perfstring, (show_body ? body_buf.buf : ""),
1198 strlen(msg) > 0 ? " - " : "", 1140 (show_body ? "\n" : ""));
1199 msg, page_len, total_time, 1141
1200 (display_html ? "</A>" : ""), 1142 return max_state_alt(result, result_ssl);
1201 perfstring,
1202 (show_body ? body_buf.buf : ""),
1203 (show_body ? "\n" : "") );
1204
1205 return max_state_alt(result, result_ssl);
1206} 1143}
1207 1144
1208int 1145int uri_strcmp(const UriTextRangeA range, const char *s) {
1209uri_strcmp (const UriTextRangeA range, const char* s) 1146 if (!range.first)
1210{ 1147 return -1;
1211 if (!range.first) return -1; 1148 if ((size_t)(range.afterLast - range.first) < strlen(s))
1212 if ( (size_t)(range.afterLast - range.first) < strlen (s) ) return -1; 1149 return -1;
1213 return strncmp (s, range.first, min( (size_t)(range.afterLast - range.first), strlen (s))); 1150 return strncmp(s, range.first, min((size_t)(range.afterLast - range.first), strlen(s)));
1214} 1151}
1215 1152
1216char* 1153char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) {
1217uri_string (const UriTextRangeA range, char* buf, size_t buflen) 1154 if (!range.first)
1218{ 1155 return "(null)";
1219 if (!range.first) return "(null)"; 1156 strncpy(buf, range.first, max(buflen - 1, (size_t)(range.afterLast - range.first)));
1220 strncpy (buf, range.first, max (buflen-1, (size_t)(range.afterLast - range.first))); 1157 buf[max(buflen - 1, (size_t)(range.afterLast - range.first))] = '\0';
1221 buf[max (buflen-1, (size_t)(range.afterLast - range.first))] = '\0'; 1158 buf[range.afterLast - range.first] = '\0';
1222 buf[range.afterLast - range.first] = '\0'; 1159 return buf;
1223 return buf;
1224} 1160}
1225 1161
1226void 1162void redir(curlhelp_write_curlbuf *header_buf) {
1227redir (curlhelp_write_curlbuf* header_buf) 1163 char *location = NULL;
1228{ 1164 curlhelp_statusline status_line;
1229 char *location = NULL; 1165 struct phr_header headers[255];
1230 curlhelp_statusline status_line; 1166 size_t nof_headers = 255;
1231 struct phr_header headers[255]; 1167 size_t msglen;
1232 size_t nof_headers = 255; 1168 char buf[DEFAULT_BUFFER_SIZE];
1233 size_t msglen; 1169 char ipstr[INET_ADDR_MAX_SIZE];
1234 char buf[DEFAULT_BUFFER_SIZE]; 1170 int new_port;
1235 char ipstr[INET_ADDR_MAX_SIZE]; 1171 char *new_host;
1236 int new_port; 1172 char *new_url;
1237 char *new_host; 1173
1238 char *new_url; 1174 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
1239 1175 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
1240 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
1241 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
1242 headers, &nof_headers, 0);
1243 1176
1244 if (res == -1) { 1177 if (res == -1) {
1245 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 1178 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
1246 } 1179 }
1247 1180
1248 location = get_header_value (headers, nof_headers, "location"); 1181 location = get_header_value(headers, nof_headers, "location");
1249 1182
1250 if (verbose >= 2) 1183 if (verbose >= 2)
1251 printf(_("* Seen redirect location %s\n"), location); 1184 printf(_("* Seen redirect location %s\n"), location);
1252 1185
1253 if (++redir_depth > max_depth) 1186 if (++redir_depth > max_depth)
1254 die (STATE_WARNING, 1187 die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"), max_depth, location,
1255 _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"), 1188 (display_html ? "</A>" : ""));
1256 max_depth, location, (display_html ? "</A>" : "")); 1189
1257 1190 UriParserStateA state;
1258 UriParserStateA state; 1191 UriUriA uri;
1259 UriUriA uri; 1192 state.uri = &uri;
1260 state.uri = &uri; 1193 if (uriParseUriA(&state, location) != URI_SUCCESS) {
1261 if (uriParseUriA (&state, location) != URI_SUCCESS) { 1194 if (state.errorCode == URI_ERROR_SYNTAX) {
1262 if (state.errorCode == URI_ERROR_SYNTAX) { 1195 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"), location, (display_html ? "</A>" : ""));
1263 die (STATE_UNKNOWN, 1196 } else if (state.errorCode == URI_ERROR_MALLOC) {
1264 _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"), 1197 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1265 location, (display_html ? "</A>" : "")); 1198 }
1266 } else if (state.errorCode == URI_ERROR_MALLOC) { 1199 }
1267 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 1200
1268 } 1201 if (verbose >= 2) {
1269 } 1202 printf(_("** scheme: %s\n"), uri_string(uri.scheme, buf, DEFAULT_BUFFER_SIZE));
1270 1203 printf(_("** host: %s\n"), uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1271 if (verbose >= 2) { 1204 printf(_("** port: %s\n"), uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
1272 printf (_("** scheme: %s\n"), 1205 if (uri.hostData.ip4) {
1273 uri_string (uri.scheme, buf, DEFAULT_BUFFER_SIZE)); 1206 inet_ntop(AF_INET, uri.hostData.ip4->data, ipstr, sizeof(ipstr));
1274 printf (_("** host: %s\n"), 1207 printf(_("** IPv4: %s\n"), ipstr);
1275 uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE)); 1208 }
1276 printf (_("** port: %s\n"), 1209 if (uri.hostData.ip6) {
1277 uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE)); 1210 inet_ntop(AF_INET, uri.hostData.ip6->data, ipstr, sizeof(ipstr));
1278 if (uri.hostData.ip4) { 1211 printf(_("** IPv6: %s\n"), ipstr);
1279 inet_ntop (AF_INET, uri.hostData.ip4->data, ipstr, sizeof (ipstr)); 1212 }
1280 printf (_("** IPv4: %s\n"), ipstr); 1213 if (uri.pathHead) {
1281 } 1214 printf(_("** path: "));
1282 if (uri.hostData.ip6) { 1215 const UriPathSegmentA *p = uri.pathHead;
1283 inet_ntop (AF_INET, uri.hostData.ip6->data, ipstr, sizeof (ipstr)); 1216 for (; p; p = p->next) {
1284 printf (_("** IPv6: %s\n"), ipstr); 1217 printf("/%s", uri_string(p->text, buf, DEFAULT_BUFFER_SIZE));
1285 } 1218 }
1286 if (uri.pathHead) { 1219 puts("");
1287 printf (_("** path: ")); 1220 }
1288 const UriPathSegmentA* p = uri.pathHead; 1221 if (uri.query.first) {
1289 for (; p; p = p->next) { 1222 printf(_("** query: %s\n"), uri_string(uri.query, buf, DEFAULT_BUFFER_SIZE));
1290 printf ("/%s", uri_string (p->text, buf, DEFAULT_BUFFER_SIZE)); 1223 }
1291 } 1224 if (uri.fragment.first) {
1292 puts (""); 1225 printf(_("** fragment: %s\n"), uri_string(uri.fragment, buf, DEFAULT_BUFFER_SIZE));
1293 } 1226 }
1294 if (uri.query.first) { 1227 }
1295 printf (_("** query: %s\n"), 1228
1296 uri_string (uri.query, buf, DEFAULT_BUFFER_SIZE)); 1229 if (uri.scheme.first) {
1297 } 1230 if (!uri_strcmp(uri.scheme, "https"))
1298 if (uri.fragment.first) { 1231 use_ssl = true;
1299 printf (_("** fragment: %s\n"), 1232 else
1300 uri_string (uri.fragment, buf, DEFAULT_BUFFER_SIZE)); 1233 use_ssl = false;
1301 } 1234 }
1302 } 1235
1303 1236 /* we do a sloppy test here only, because uriparser would have failed
1304 if (uri.scheme.first) { 1237 * above, if the port would be invalid, we just check for MAX_PORT
1305 if (!uri_strcmp (uri.scheme, "https")) 1238 */
1306 use_ssl = true; 1239 if (uri.portText.first) {
1307 else 1240 new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
1308 use_ssl = false; 1241 } else {
1309 } 1242 new_port = HTTP_PORT;
1310 1243 if (use_ssl)
1311 /* we do a sloppy test here only, because uriparser would have failed 1244 new_port = HTTPS_PORT;
1312 * above, if the port would be invalid, we just check for MAX_PORT 1245 }
1313 */ 1246 if (new_port > MAX_PORT)
1314 if (uri.portText.first) { 1247 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"), MAX_PORT, location, display_html ? "</A>" : "");
1315 new_port = atoi (uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE)); 1248
1316 } else { 1249 /* by RFC 7231 relative URLs in Location should be taken relative to
1317 new_port = HTTP_PORT; 1250 * the original URL, so we try to form a new absolute URL here
1318 if (use_ssl) 1251 */
1319 new_port = HTTPS_PORT; 1252 if (!uri.scheme.first && !uri.hostText.first) {
1320 } 1253 new_host = strdup(host_name ? host_name : server_address);
1321 if (new_port > MAX_PORT) 1254 new_port = server_port;
1322 die (STATE_UNKNOWN, 1255 if (use_ssl)
1323 _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"), 1256 uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE);
1324 MAX_PORT, location, display_html ? "</A>" : ""); 1257 } else {
1325 1258 new_host = strdup(uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1326 /* by RFC 7231 relative URLs in Location should be taken relative to 1259 }
1327 * the original URL, so we try to form a new absolute URL here 1260
1328 */ 1261 /* compose new path */
1329 if (!uri.scheme.first && !uri.hostText.first) { 1262 /* TODO: handle fragments and query part of URL */
1330 new_host = strdup (host_name ? host_name : server_address); 1263 new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE);
1331 new_port = server_port; 1264 if (uri.pathHead) {
1332 if(use_ssl) 1265 const UriPathSegmentA *p = uri.pathHead;
1333 uri_string (uri.scheme, "https", DEFAULT_BUFFER_SIZE); 1266 for (; p; p = p->next) {
1334 } else { 1267 strncat(new_url, "/", DEFAULT_BUFFER_SIZE);
1335 new_host = strdup (uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE)); 1268 strncat(new_url, uri_string(p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE - 1);
1336 } 1269 }
1337 1270 }
1338 /* compose new path */ 1271
1339 /* TODO: handle fragments and query part of URL */ 1272 if (server_port == new_port && !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) &&
1340 new_url = (char *)calloc( 1, DEFAULT_BUFFER_SIZE); 1273 (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && !strcmp(server_url, new_url))
1341 if (uri.pathHead) { 1274 die(STATE_CRITICAL, _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), use_ssl ? "https" : "http",
1342 const UriPathSegmentA* p = uri.pathHead; 1275 new_host, new_port, new_url, (display_html ? "</A>" : ""));
1343 for (; p; p = p->next) { 1276
1344 strncat (new_url, "/", DEFAULT_BUFFER_SIZE); 1277 /* set new values for redirected request */
1345 strncat (new_url, uri_string (p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE-1); 1278
1346 } 1279 if (!(followsticky & STICKY_HOST)) {
1347 } 1280 free(server_address);
1348 1281 server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1349 if (server_port==new_port && 1282 }
1350 !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) && 1283 if (!(followsticky & STICKY_PORT)) {
1351 (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && 1284 server_port = (unsigned short)new_port;
1352 !strcmp(server_url, new_url)) 1285 }
1353 die (STATE_CRITICAL, 1286
1354 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), 1287 free(host_name);
1355 use_ssl ? "https" : "http", new_host, new_port, new_url, (display_html ? "</A>" : "")); 1288 host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1356 1289
1357 /* set new values for redirected request */ 1290 /* reset virtual port */
1358 1291 virtual_port = server_port;
1359 if (!(followsticky & STICKY_HOST)) { 1292
1360 free (server_address); 1293 free(new_host);
1361 server_address = strndup (new_host, MAX_IPV4_HOSTLENGTH); 1294 free(server_url);
1362 } 1295 server_url = new_url;
1363 if (!(followsticky & STICKY_PORT)) { 1296
1364 server_port = (unsigned short)new_port; 1297 uriFreeUriMembersA(&uri);
1365 } 1298
1366 1299 if (verbose)
1367 free (host_name); 1300 printf(_("Redirection to %s://%s:%d%s\n"), use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port,
1368 host_name = strndup (new_host, MAX_IPV4_HOSTLENGTH); 1301 server_url);
1369 1302
1370 /* reset virtual port */ 1303 /* TODO: the hash component MUST be taken from the original URL and
1371 virtual_port = server_port; 1304 * attached to the URL in Location
1372 1305 */
1373 free(new_host); 1306
1374 free (server_url); 1307 cleanup();
1375 server_url = new_url; 1308 check_http();
1376
1377 uriFreeUriMembersA (&uri);
1378
1379 if (verbose)
1380 printf (_("Redirection to %s://%s:%d%s\n"), use_ssl ? "https" : "http",
1381 host_name ? host_name : server_address, server_port, server_url);
1382
1383 /* TODO: the hash component MUST be taken from the original URL and
1384 * attached to the URL in Location
1385 */
1386
1387 cleanup ();
1388 check_http ();
1389} 1309}
1390 1310
1391/* check whether a file exists */ 1311/* check whether a file exists */
1392void 1312void test_file(char *path) {
1393test_file (char *path) 1313 if (access(path, R_OK) == 0)
1394{ 1314 return;
1395 if (access(path, R_OK) == 0) 1315 usage2(_("file does not exist or is not readable"), path);
1396 return;
1397 usage2 (_("file does not exist or is not readable"), path);
1398} 1316}
1399 1317
1400bool 1318bool process_arguments(int argc, char **argv) {
1401process_arguments (int argc, char **argv) 1319 char *p;
1402{ 1320 int c = 1;
1403 char *p; 1321 char *temp;
1404 int c = 1; 1322
1405 char *temp; 1323 enum {
1406 1324 INVERT_REGEX = CHAR_MAX + 1,
1407 enum { 1325 SNI_OPTION,
1408 INVERT_REGEX = CHAR_MAX + 1, 1326 MAX_REDIRS_OPTION,
1409 SNI_OPTION, 1327 CONTINUE_AFTER_CHECK_CERT,
1410 MAX_REDIRS_OPTION, 1328 CA_CERT_OPTION,
1411 CONTINUE_AFTER_CHECK_CERT, 1329 HTTP_VERSION_OPTION,
1412 CA_CERT_OPTION, 1330 AUTOMATIC_DECOMPRESSION,
1413 HTTP_VERSION_OPTION, 1331 COOKIE_JAR,
1414 AUTOMATIC_DECOMPRESSION, 1332 HAPROXY_PROTOCOL,
1415 COOKIE_JAR, 1333 STATE_REGEX
1416 HAPROXY_PROTOCOL, 1334 };
1417 STATE_REGEX 1335
1418 }; 1336 int option = 0;
1419 1337 int got_plus = 0;
1420 int option = 0; 1338 static struct option longopts[] = {STD_LONG_OPTS,
1421 int got_plus = 0; 1339 {"link", no_argument, 0, 'L'},
1422 static struct option longopts[] = { 1340 {"nohtml", no_argument, 0, 'n'},
1423 STD_LONG_OPTS, 1341 {"ssl", optional_argument, 0, 'S'},
1424 {"link", no_argument, 0, 'L'}, 1342 {"sni", no_argument, 0, SNI_OPTION},
1425 {"nohtml", no_argument, 0, 'n'}, 1343 {"post", required_argument, 0, 'P'},
1426 {"ssl", optional_argument, 0, 'S'}, 1344 {"method", required_argument, 0, 'j'},
1427 {"sni", no_argument, 0, SNI_OPTION}, 1345 {"IP-address", required_argument, 0, 'I'},
1428 {"post", required_argument, 0, 'P'}, 1346 {"url", required_argument, 0, 'u'},
1429 {"method", required_argument, 0, 'j'}, 1347 {"port", required_argument, 0, 'p'},
1430 {"IP-address", required_argument, 0, 'I'}, 1348 {"authorization", required_argument, 0, 'a'},
1431 {"url", required_argument, 0, 'u'}, 1349 {"proxy-authorization", required_argument, 0, 'b'},
1432 {"port", required_argument, 0, 'p'}, 1350 {"header-string", required_argument, 0, 'd'},
1433 {"authorization", required_argument, 0, 'a'}, 1351 {"string", required_argument, 0, 's'},
1434 {"proxy-authorization", required_argument, 0, 'b'}, 1352 {"expect", required_argument, 0, 'e'},
1435 {"header-string", required_argument, 0, 'd'}, 1353 {"regex", required_argument, 0, 'r'},
1436 {"string", required_argument, 0, 's'}, 1354 {"ereg", required_argument, 0, 'r'},
1437 {"expect", required_argument, 0, 'e'}, 1355 {"eregi", required_argument, 0, 'R'},
1438 {"regex", required_argument, 0, 'r'}, 1356 {"linespan", no_argument, 0, 'l'},
1439 {"ereg", required_argument, 0, 'r'}, 1357 {"onredirect", required_argument, 0, 'f'},
1440 {"eregi", required_argument, 0, 'R'}, 1358 {"certificate", required_argument, 0, 'C'},
1441 {"linespan", no_argument, 0, 'l'}, 1359 {"client-cert", required_argument, 0, 'J'},
1442 {"onredirect", required_argument, 0, 'f'}, 1360 {"private-key", required_argument, 0, 'K'},
1443 {"certificate", required_argument, 0, 'C'}, 1361 {"ca-cert", required_argument, 0, CA_CERT_OPTION},
1444 {"client-cert", required_argument, 0, 'J'}, 1362 {"verify-cert", no_argument, 0, 'D'},
1445 {"private-key", required_argument, 0, 'K'}, 1363 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
1446 {"ca-cert", required_argument, 0, CA_CERT_OPTION}, 1364 {"useragent", required_argument, 0, 'A'},
1447 {"verify-cert", no_argument, 0, 'D'}, 1365 {"header", required_argument, 0, 'k'},
1448 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT}, 1366 {"no-body", no_argument, 0, 'N'},
1449 {"useragent", required_argument, 0, 'A'}, 1367 {"max-age", required_argument, 0, 'M'},
1450 {"header", required_argument, 0, 'k'}, 1368 {"content-type", required_argument, 0, 'T'},
1451 {"no-body", no_argument, 0, 'N'}, 1369 {"pagesize", required_argument, 0, 'm'},
1452 {"max-age", required_argument, 0, 'M'}, 1370 {"invert-regex", no_argument, NULL, INVERT_REGEX},
1453 {"content-type", required_argument, 0, 'T'}, 1371 {"state-regex", required_argument, 0, STATE_REGEX},
1454 {"pagesize", required_argument, 0, 'm'}, 1372 {"use-ipv4", no_argument, 0, '4'},
1455 {"invert-regex", no_argument, NULL, INVERT_REGEX}, 1373 {"use-ipv6", no_argument, 0, '6'},
1456 {"state-regex", required_argument, 0, STATE_REGEX}, 1374 {"extended-perfdata", no_argument, 0, 'E'},
1457 {"use-ipv4", no_argument, 0, '4'}, 1375 {"show-body", no_argument, 0, 'B'},
1458 {"use-ipv6", no_argument, 0, '6'}, 1376 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
1459 {"extended-perfdata", no_argument, 0, 'E'}, 1377 {"http-version", required_argument, 0, HTTP_VERSION_OPTION},
1460 {"show-body", no_argument, 0, 'B'}, 1378 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION},
1461 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION}, 1379 {"cookie-jar", required_argument, 0, COOKIE_JAR},
1462 {"http-version", required_argument, 0, HTTP_VERSION_OPTION}, 1380 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL},
1463 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION}, 1381 {0, 0, 0, 0}};
1464 {"cookie-jar", required_argument, 0, COOKIE_JAR}, 1382
1465 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL}, 1383 if (argc < 2)
1466 {0, 0, 0, 0} 1384 return false;
1467 }; 1385
1468 1386 /* support check_http compatible arguments */
1469 if (argc < 2) 1387 for (c = 1; c < argc; c++) {
1470 return false; 1388 if (strcmp("-to", argv[c]) == 0)
1471 1389 strcpy(argv[c], "-t");
1472 /* support check_http compatible arguments */ 1390 if (strcmp("-hn", argv[c]) == 0)
1473 for (c = 1; c < argc; c++) { 1391 strcpy(argv[c], "-H");
1474 if (strcmp ("-to", argv[c]) == 0) 1392 if (strcmp("-wt", argv[c]) == 0)
1475 strcpy (argv[c], "-t"); 1393 strcpy(argv[c], "-w");
1476 if (strcmp ("-hn", argv[c]) == 0) 1394 if (strcmp("-ct", argv[c]) == 0)
1477 strcpy (argv[c], "-H"); 1395 strcpy(argv[c], "-c");
1478 if (strcmp ("-wt", argv[c]) == 0) 1396 if (strcmp("-nohtml", argv[c]) == 0)
1479 strcpy (argv[c], "-w"); 1397 strcpy(argv[c], "-n");
1480 if (strcmp ("-ct", argv[c]) == 0) 1398 }
1481 strcpy (argv[c], "-c"); 1399
1482 if (strcmp ("-nohtml", argv[c]) == 0) 1400 server_url = strdup(DEFAULT_SERVER_URL);
1483 strcpy (argv[c], "-n"); 1401
1484 } 1402 while (1) {
1485 1403 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:DnlLS::m:M:NEB", longopts, &option);
1486 server_url = strdup(DEFAULT_SERVER_URL); 1404 if (c == -1 || c == EOF || c == 1)
1487 1405 break;
1488 while (1) { 1406
1489 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:DnlLS::m:M:NEB", longopts, &option); 1407 switch (c) {
1490 if (c == -1 || c == EOF || c == 1) 1408 case 'h':
1491 break; 1409 print_help();
1492 1410 exit(STATE_UNKNOWN);
1493 switch (c) { 1411 break;
1494 case 'h': 1412 case 'V':
1495 print_help(); 1413 print_revision(progname, NP_VERSION);
1496 exit(STATE_UNKNOWN); 1414 print_curl_version();
1497 break; 1415 exit(STATE_UNKNOWN);
1498 case 'V': 1416 break;
1499 print_revision(progname, NP_VERSION); 1417 case 'v':
1500 print_curl_version(); 1418 verbose++;
1501 exit(STATE_UNKNOWN); 1419 break;
1502 break; 1420 case 't': /* timeout period */
1503 case 'v': 1421 if (!is_intnonneg(optarg))
1504 verbose++; 1422 usage2(_("Timeout interval must be a positive integer"), optarg);
1505 break; 1423 else
1506 case 't': /* timeout period */ 1424 socket_timeout = (int)strtol(optarg, NULL, 10);
1507 if (!is_intnonneg (optarg)) 1425 break;
1508 usage2 (_("Timeout interval must be a positive integer"), optarg); 1426 case 'c': /* critical time threshold */
1509 else 1427 critical_thresholds = optarg;
1510 socket_timeout = (int)strtol (optarg, NULL, 10); 1428 break;
1511 break; 1429 case 'w': /* warning time threshold */
1512 case 'c': /* critical time threshold */ 1430 warning_thresholds = optarg;
1513 critical_thresholds = optarg; 1431 break;
1514 break; 1432 case 'H': /* virtual host */
1515 case 'w': /* warning time threshold */ 1433 host_name = strdup(optarg);
1516 warning_thresholds = optarg; 1434 if (host_name[0] == '[') {
1517 break; 1435 if ((p = strstr(host_name, "]:")) != NULL) { /* [IPv6]:port */
1518 case 'H': /* virtual host */ 1436 virtual_port = atoi(p + 2);
1519 host_name = strdup (optarg); 1437 /* cut off the port */
1520 if (host_name[0] == '[') { 1438 host_name_length = strlen(host_name) - strlen(p) - 1;
1521 if ((p = strstr (host_name, "]:")) != NULL) { /* [IPv6]:port */ 1439 free(host_name);
1522 virtual_port = atoi (p + 2); 1440 host_name = strndup(optarg, host_name_length);
1523 /* cut off the port */ 1441 }
1524 host_name_length = strlen (host_name) - strlen (p) - 1; 1442 } else if ((p = strchr(host_name, ':')) != NULL && strchr(++p, ':') == NULL) { /* IPv4:port or host:port */
1525 free (host_name); 1443 virtual_port = atoi(p);
1526 host_name = strndup (optarg, host_name_length); 1444 /* cut off the port */
1527 } 1445 host_name_length = strlen(host_name) - strlen(p) - 1;
1528 } else if ((p = strchr (host_name, ':')) != NULL 1446 free(host_name);
1529 && strchr (++p, ':') == NULL) { /* IPv4:port or host:port */ 1447 host_name = strndup(optarg, host_name_length);
1530 virtual_port = atoi (p); 1448 }
1531 /* cut off the port */ 1449 break;
1532 host_name_length = strlen (host_name) - strlen (p) - 1; 1450 case 'I': /* internet address */
1533 free (host_name); 1451 server_address = strdup(optarg);
1534 host_name = strndup (optarg, host_name_length); 1452 break;
1535 } 1453 case 'u': /* URL path */
1536 break; 1454 server_url = strdup(optarg);
1537 case 'I': /* internet address */ 1455 break;
1538 server_address = strdup (optarg); 1456 case 'p': /* Server port */
1539 break; 1457 if (!is_intnonneg(optarg))
1540 case 'u': /* URL path */ 1458 usage2(_("Invalid port number, expecting a non-negative number"), optarg);
1541 server_url = strdup (optarg); 1459 else {
1542 break; 1460 if (strtol(optarg, NULL, 10) > MAX_PORT)
1543 case 'p': /* Server port */ 1461 usage2(_("Invalid port number, supplied port number is too big"), optarg);
1544 if (!is_intnonneg (optarg)) 1462 server_port = (unsigned short)strtol(optarg, NULL, 10);
1545 usage2 (_("Invalid port number, expecting a non-negative number"), optarg); 1463 specify_port = true;
1546 else { 1464 }
1547 if( strtol(optarg, NULL, 10) > MAX_PORT) 1465 break;
1548 usage2 (_("Invalid port number, supplied port number is too big"), optarg); 1466 case 'a': /* authorization info */
1549 server_port = (unsigned short)strtol(optarg, NULL, 10); 1467 strncpy(user_auth, optarg, MAX_INPUT_BUFFER - 1);
1550 specify_port = true; 1468 user_auth[MAX_INPUT_BUFFER - 1] = 0;
1551 } 1469 break;
1552 break; 1470 case 'b': /* proxy-authorization info */
1553 case 'a': /* authorization info */ 1471 strncpy(proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
1554 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1); 1472 proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
1555 user_auth[MAX_INPUT_BUFFER - 1] = 0; 1473 break;
1556 break; 1474 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
1557 case 'b': /* proxy-authorization info */ 1475 if (!http_post_data)
1558 strncpy (proxy_auth, optarg, MAX_INPUT_BUFFER - 1); 1476 http_post_data = strdup(optarg);
1559 proxy_auth[MAX_INPUT_BUFFER - 1] = 0; 1477 if (!http_method)
1560 break; 1478 http_method = strdup("POST");
1561 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */ 1479 break;
1562 if (! http_post_data) 1480 case 'j': /* Set HTTP method */
1563 http_post_data = strdup (optarg); 1481 if (http_method)
1564 if (! http_method) 1482 free(http_method);
1565 http_method = strdup("POST"); 1483 http_method = strdup(optarg);
1566 break; 1484 break;
1567 case 'j': /* Set HTTP method */ 1485 case 'A': /* useragent */
1568 if (http_method) 1486 strncpy(user_agent, optarg, DEFAULT_BUFFER_SIZE);
1569 free(http_method); 1487 user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0';
1570 http_method = strdup (optarg); 1488 break;
1571 break; 1489 case 'k': /* Additional headers */
1572 case 'A': /* useragent */ 1490 if (http_opt_headers_count == 0)
1573 strncpy (user_agent, optarg, DEFAULT_BUFFER_SIZE); 1491 http_opt_headers = malloc(sizeof(char *) * (++http_opt_headers_count));
1574 user_agent[DEFAULT_BUFFER_SIZE-1] = '\0'; 1492 else
1575 break; 1493 http_opt_headers = realloc(http_opt_headers, sizeof(char *) * (++http_opt_headers_count));
1576 case 'k': /* Additional headers */ 1494 http_opt_headers[http_opt_headers_count - 1] = optarg;
1577 if (http_opt_headers_count == 0) 1495 break;
1578 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count)); 1496 case 'L': /* show html link */
1579 else 1497 display_html = true;
1580 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count)); 1498 break;
1581 http_opt_headers[http_opt_headers_count - 1] = optarg; 1499 case 'n': /* do not show html link */
1582 break; 1500 display_html = false;
1583 case 'L': /* show html link */ 1501 break;
1584 display_html = true; 1502 case 'C': /* Check SSL cert validity */
1585 break;
1586 case 'n': /* do not show html link */
1587 display_html = false;
1588 break;
1589 case 'C': /* Check SSL cert validity */
1590#ifdef LIBCURL_FEATURE_SSL 1503#ifdef LIBCURL_FEATURE_SSL
1591 if ((temp=strchr(optarg,','))!=NULL) { 1504 if ((temp = strchr(optarg, ',')) != NULL) {
1592 *temp='\0'; 1505 *temp = '\0';
1593 if (!is_intnonneg (optarg)) 1506 if (!is_intnonneg(optarg))
1594 usage2 (_("Invalid certificate expiration period"), optarg); 1507 usage2(_("Invalid certificate expiration period"), optarg);
1595 days_till_exp_warn = atoi(optarg); 1508 days_till_exp_warn = atoi(optarg);
1596 *temp=','; 1509 *temp = ',';
1597 temp++; 1510 temp++;
1598 if (!is_intnonneg (temp)) 1511 if (!is_intnonneg(temp))
1599 usage2 (_("Invalid certificate expiration period"), temp); 1512 usage2(_("Invalid certificate expiration period"), temp);
1600 days_till_exp_crit = atoi (temp); 1513 days_till_exp_crit = atoi(temp);
1601 } 1514 } else {
1602 else { 1515 days_till_exp_crit = 0;
1603 days_till_exp_crit=0; 1516 if (!is_intnonneg(optarg))
1604 if (!is_intnonneg (optarg)) 1517 usage2(_("Invalid certificate expiration period"), optarg);
1605 usage2 (_("Invalid certificate expiration period"), optarg); 1518 days_till_exp_warn = atoi(optarg);
1606 days_till_exp_warn = atoi (optarg); 1519 }
1607 } 1520 check_cert = true;
1608 check_cert = true; 1521 goto enable_ssl;
1609 goto enable_ssl;
1610#endif 1522#endif
1611 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */ 1523 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
1612#ifdef HAVE_SSL 1524#ifdef HAVE_SSL
1613 continue_after_check_cert = true; 1525 continue_after_check_cert = true;
1614 break; 1526 break;
1615#endif 1527#endif
1616 case 'J': /* use client certificate */ 1528 case 'J': /* use client certificate */
1617#ifdef LIBCURL_FEATURE_SSL 1529#ifdef LIBCURL_FEATURE_SSL
1618 test_file(optarg); 1530 test_file(optarg);
1619 client_cert = optarg; 1531 client_cert = optarg;
1620 goto enable_ssl; 1532 goto enable_ssl;
1621#endif 1533#endif
1622 case 'K': /* use client private key */ 1534 case 'K': /* use client private key */
1623#ifdef LIBCURL_FEATURE_SSL 1535#ifdef LIBCURL_FEATURE_SSL
1624 test_file(optarg); 1536 test_file(optarg);
1625 client_privkey = optarg; 1537 client_privkey = optarg;
1626 goto enable_ssl; 1538 goto enable_ssl;
1627#endif 1539#endif
1628#ifdef LIBCURL_FEATURE_SSL 1540#ifdef LIBCURL_FEATURE_SSL
1629 case CA_CERT_OPTION: /* use CA chain file */ 1541 case CA_CERT_OPTION: /* use CA chain file */
1630 test_file(optarg); 1542 test_file(optarg);
1631 ca_cert = optarg; 1543 ca_cert = optarg;
1632 goto enable_ssl; 1544 goto enable_ssl;
1633#endif 1545#endif
1634#ifdef LIBCURL_FEATURE_SSL 1546#ifdef LIBCURL_FEATURE_SSL
1635 case 'D': /* verify peer certificate & host */ 1547 case 'D': /* verify peer certificate & host */
1636 verify_peer_and_host = true; 1548 verify_peer_and_host = true;
1637 break; 1549 break;
1638#endif 1550#endif
1639 case 'S': /* use SSL */ 1551 case 'S': /* use SSL */
1640#ifdef LIBCURL_FEATURE_SSL 1552#ifdef LIBCURL_FEATURE_SSL
1641 enable_ssl: 1553 enable_ssl:
1642 use_ssl = true; 1554 use_ssl = true;
1643 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default. 1555 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
1644 * Only set if it's non-zero. This helps when we include multiple 1556 * Only set if it's non-zero. This helps when we include multiple
1645 * parameters, like -S and -C combinations */ 1557 * parameters, like -S and -C combinations */
1646 ssl_version = CURL_SSLVERSION_DEFAULT; 1558 ssl_version = CURL_SSLVERSION_DEFAULT;
1647 if (c=='S' && optarg != NULL) { 1559 if (c == 'S' && optarg != NULL) {
1648 char *plus_ptr = strchr(optarg, '+'); 1560 char *plus_ptr = strchr(optarg, '+');
1649 if (plus_ptr) { 1561 if (plus_ptr) {
1650 got_plus = 1; 1562 got_plus = 1;
1651 *plus_ptr = '\0'; 1563 *plus_ptr = '\0';
1652 } 1564 }
1653 1565
1654 if (optarg[0] == '2') 1566 if (optarg[0] == '2')
1655 ssl_version = CURL_SSLVERSION_SSLv2; 1567 ssl_version = CURL_SSLVERSION_SSLv2;
1656 else if (optarg[0] == '3') 1568 else if (optarg[0] == '3')
1657 ssl_version = CURL_SSLVERSION_SSLv3; 1569 ssl_version = CURL_SSLVERSION_SSLv3;
1658 else if (!strcmp (optarg, "1") || !strcmp (optarg, "1.0")) 1570 else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0"))
1659#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1571# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1660 ssl_version = CURL_SSLVERSION_TLSv1_0; 1572 ssl_version = CURL_SSLVERSION_TLSv1_0;
1661#else 1573# else
1662 ssl_version = CURL_SSLVERSION_DEFAULT; 1574 ssl_version = CURL_SSLVERSION_DEFAULT;
1663#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1575# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1664 else if (!strcmp (optarg, "1.1")) 1576 else if (!strcmp(optarg, "1.1"))
1665#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1577# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1666 ssl_version = CURL_SSLVERSION_TLSv1_1; 1578 ssl_version = CURL_SSLVERSION_TLSv1_1;
1667#else 1579# else
1668 ssl_version = CURL_SSLVERSION_DEFAULT; 1580 ssl_version = CURL_SSLVERSION_DEFAULT;
1669#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1581# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1670 else if (!strcmp (optarg, "1.2")) 1582 else if (!strcmp(optarg, "1.2"))
1671#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1583# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1672 ssl_version = CURL_SSLVERSION_TLSv1_2; 1584 ssl_version = CURL_SSLVERSION_TLSv1_2;
1673#else 1585# else
1674 ssl_version = CURL_SSLVERSION_DEFAULT; 1586 ssl_version = CURL_SSLVERSION_DEFAULT;
1675#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1587# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1676 else if (!strcmp (optarg, "1.3")) 1588 else if (!strcmp(optarg, "1.3"))
1677#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) 1589# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
1678 ssl_version = CURL_SSLVERSION_TLSv1_3; 1590 ssl_version = CURL_SSLVERSION_TLSv1_3;
1679#else 1591# else
1680 ssl_version = CURL_SSLVERSION_DEFAULT; 1592 ssl_version = CURL_SSLVERSION_DEFAULT;
1681#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */ 1593# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
1682 else 1594 else
1683 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)")); 1595 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)"));
1684 } 1596 }
1685#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) 1597# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
1686 if (got_plus) { 1598 if (got_plus) {
1687 switch (ssl_version) { 1599 switch (ssl_version) {
1688 case CURL_SSLVERSION_TLSv1_3: 1600 case CURL_SSLVERSION_TLSv1_3:
1689 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1601 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1690 break; 1602 break;
1691 case CURL_SSLVERSION_TLSv1_2: 1603 case CURL_SSLVERSION_TLSv1_2:
1692 case CURL_SSLVERSION_TLSv1_1: 1604 case CURL_SSLVERSION_TLSv1_1:
1693 case CURL_SSLVERSION_TLSv1_0: 1605 case CURL_SSLVERSION_TLSv1_0:
1694 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT; 1606 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
1695 break; 1607 break;
1696 } 1608 }
1697 } else { 1609 } else {
1698 switch (ssl_version) { 1610 switch (ssl_version) {
1699 case CURL_SSLVERSION_TLSv1_3: 1611 case CURL_SSLVERSION_TLSv1_3:
1700 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1612 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1701 break; 1613 break;
1702 case CURL_SSLVERSION_TLSv1_2: 1614 case CURL_SSLVERSION_TLSv1_2:
1703 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2; 1615 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
1704 break; 1616 break;
1705 case CURL_SSLVERSION_TLSv1_1: 1617 case CURL_SSLVERSION_TLSv1_1:
1706 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1; 1618 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
1707 break; 1619 break;
1708 case CURL_SSLVERSION_TLSv1_0: 1620 case CURL_SSLVERSION_TLSv1_0:
1709 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0; 1621 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
1710 break; 1622 break;
1711 } 1623 }
1712 } 1624 }
1713#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ 1625# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1714 if (verbose >= 2) 1626 if (verbose >= 2)
1715 printf(_("* Set SSL/TLS version to %d\n"), ssl_version); 1627 printf(_("* Set SSL/TLS version to %d\n"), ssl_version);
1716 if (!specify_port) 1628 if (!specify_port)
1717 server_port = HTTPS_PORT; 1629 server_port = HTTPS_PORT;
1718 break; 1630 break;
1719#else /* LIBCURL_FEATURE_SSL */ 1631#else /* LIBCURL_FEATURE_SSL */
1720 /* -C -J and -K fall through to here without SSL */ 1632 /* -C -J and -K fall through to here without SSL */
1721 usage4 (_("Invalid option - SSL is not available")); 1633 usage4(_("Invalid option - SSL is not available"));
1722 break; 1634 break;
1723 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */ 1635 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */
1724 use_sni = true; 1636 use_sni = true;
1725 break; 1637 break;
1726#endif /* LIBCURL_FEATURE_SSL */ 1638#endif /* LIBCURL_FEATURE_SSL */
1727 case MAX_REDIRS_OPTION: 1639 case MAX_REDIRS_OPTION:
1728 if (!is_intnonneg (optarg)) 1640 if (!is_intnonneg(optarg))
1729 usage2 (_("Invalid max_redirs count"), optarg); 1641 usage2(_("Invalid max_redirs count"), optarg);
1730 else { 1642 else {
1731 max_depth = atoi (optarg); 1643 max_depth = atoi(optarg);
1732 } 1644 }
1733 break; 1645 break;
1734 case 'f': /* onredirect */ 1646 case 'f': /* onredirect */
1735 if (!strcmp (optarg, "ok")) 1647 if (!strcmp(optarg, "ok"))
1736 onredirect = STATE_OK; 1648 onredirect = STATE_OK;
1737 else if (!strcmp (optarg, "warning")) 1649 else if (!strcmp(optarg, "warning"))
1738 onredirect = STATE_WARNING; 1650 onredirect = STATE_WARNING;
1739 else if (!strcmp (optarg, "critical")) 1651 else if (!strcmp(optarg, "critical"))
1740 onredirect = STATE_CRITICAL; 1652 onredirect = STATE_CRITICAL;
1741 else if (!strcmp (optarg, "unknown")) 1653 else if (!strcmp(optarg, "unknown"))
1742 onredirect = STATE_UNKNOWN; 1654 onredirect = STATE_UNKNOWN;
1743 else if (!strcmp (optarg, "follow")) 1655 else if (!strcmp(optarg, "follow"))
1744 onredirect = STATE_DEPENDENT; 1656 onredirect = STATE_DEPENDENT;
1745 else if (!strcmp (optarg, "stickyport")) 1657 else if (!strcmp(optarg, "stickyport"))
1746 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST|STICKY_PORT; 1658 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST | STICKY_PORT;
1747 else if (!strcmp (optarg, "sticky")) 1659 else if (!strcmp(optarg, "sticky"))
1748 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST; 1660 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST;
1749 else if (!strcmp (optarg, "follow")) 1661 else if (!strcmp(optarg, "follow"))
1750 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE; 1662 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE;
1751 else if (!strcmp (optarg, "curl")) 1663 else if (!strcmp(optarg, "curl"))
1752 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL; 1664 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL;
1753 else usage2 (_("Invalid onredirect option"), optarg); 1665 else
1754 if (verbose >= 2) 1666 usage2(_("Invalid onredirect option"), optarg);
1755 printf(_("* Following redirects set to %s\n"), state_text(onredirect)); 1667 if (verbose >= 2)
1756 break; 1668 printf(_("* Following redirects set to %s\n"), state_text(onredirect));
1757 case 'd': /* string or substring */ 1669 break;
1758 strncpy (header_expect, optarg, MAX_INPUT_BUFFER - 1); 1670 case 'd': /* string or substring */
1759 header_expect[MAX_INPUT_BUFFER - 1] = 0; 1671 strncpy(header_expect, optarg, MAX_INPUT_BUFFER - 1);
1760 break; 1672 header_expect[MAX_INPUT_BUFFER - 1] = 0;
1761 case 's': /* string or substring */ 1673 break;
1762 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1); 1674 case 's': /* string or substring */
1763 string_expect[MAX_INPUT_BUFFER - 1] = 0; 1675 strncpy(string_expect, optarg, MAX_INPUT_BUFFER - 1);
1764 break; 1676 string_expect[MAX_INPUT_BUFFER - 1] = 0;
1765 case 'e': /* string or substring */ 1677 break;
1766 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1); 1678 case 'e': /* string or substring */
1767 server_expect[MAX_INPUT_BUFFER - 1] = 0; 1679 strncpy(server_expect, optarg, MAX_INPUT_BUFFER - 1);
1768 server_expect_yn = 1; 1680 server_expect[MAX_INPUT_BUFFER - 1] = 0;
1769 break; 1681 server_expect_yn = 1;
1770 case 'T': /* Content-type */ 1682 break;
1771 http_content_type = strdup (optarg); 1683 case 'T': /* Content-type */
1772 break; 1684 http_content_type = strdup(optarg);
1773 case 'l': /* linespan */ 1685 break;
1774 cflags &= ~REG_NEWLINE; 1686 case 'l': /* linespan */
1775 break; 1687 cflags &= ~REG_NEWLINE;
1776 case 'R': /* regex */ 1688 break;
1777 cflags |= REG_ICASE; 1689 case 'R': /* regex */
1690 cflags |= REG_ICASE;
1778 // fall through 1691 // fall through
1779 case 'r': /* regex */ 1692 case 'r': /* regex */
1780 strncpy (regexp, optarg, MAX_RE_SIZE - 1); 1693 strncpy(regexp, optarg, MAX_RE_SIZE - 1);
1781 regexp[MAX_RE_SIZE - 1] = 0; 1694 regexp[MAX_RE_SIZE - 1] = 0;
1782 errcode = regcomp (&preg, regexp, cflags); 1695 errcode = regcomp(&preg, regexp, cflags);
1783 if (errcode != 0) { 1696 if (errcode != 0) {
1784 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1697 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1785 printf (_("Could Not Compile Regular Expression: %s"), errbuf); 1698 printf(_("Could Not Compile Regular Expression: %s"), errbuf);
1786 return false; 1699 return false;
1787 } 1700 }
1788 break; 1701 break;
1789 case INVERT_REGEX: 1702 case INVERT_REGEX:
1790 invert_regex = true; 1703 invert_regex = true;
1791 break; 1704 break;
1792 case STATE_REGEX: 1705 case STATE_REGEX:
1793 if (!strcasecmp (optarg, "critical")) 1706 if (!strcasecmp(optarg, "critical"))
1794 state_regex = STATE_CRITICAL; 1707 state_regex = STATE_CRITICAL;
1795 else if (!strcasecmp (optarg, "warning")) 1708 else if (!strcasecmp(optarg, "warning"))
1796 state_regex = STATE_WARNING; 1709 state_regex = STATE_WARNING;
1797 else usage2 (_("Invalid state-regex option"), optarg); 1710 else
1798 break; 1711 usage2(_("Invalid state-regex option"), optarg);
1799 case '4': 1712 break;
1800 address_family = AF_INET; 1713 case '4':
1801 break; 1714 address_family = AF_INET;
1802 case '6': 1715 break;
1803#if defined (USE_IPV6) && defined (LIBCURL_FEATURE_IPV6) 1716 case '6':
1804 address_family = AF_INET6; 1717#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
1718 address_family = AF_INET6;
1805#else 1719#else
1806 usage4 (_("IPv6 support not available")); 1720 usage4(_("IPv6 support not available"));
1807#endif 1721#endif
1808 break; 1722 break;
1809 case 'm': /* min_page_length */ 1723 case 'm': /* min_page_length */
1810 { 1724 {
1811 char *tmp; 1725 char *tmp;
1812 if (strchr(optarg, ':') != (char *)NULL) { 1726 if (strchr(optarg, ':') != (char *)NULL) {
1813 /* range, so get two values, min:max */ 1727 /* range, so get two values, min:max */
1814 tmp = strtok(optarg, ":"); 1728 tmp = strtok(optarg, ":");
1815 if (tmp == NULL) { 1729 if (tmp == NULL) {
1816 printf("Bad format: try \"-m min:max\"\n"); 1730 printf("Bad format: try \"-m min:max\"\n");
1817 exit (STATE_WARNING); 1731 exit(STATE_WARNING);
1818 } else 1732 } else
1819 min_page_len = atoi(tmp); 1733 min_page_len = atoi(tmp);
1820 1734
1821 tmp = strtok(NULL, ":"); 1735 tmp = strtok(NULL, ":");
1822 if (tmp == NULL) { 1736 if (tmp == NULL) {
1823 printf("Bad format: try \"-m min:max\"\n"); 1737 printf("Bad format: try \"-m min:max\"\n");
1824 exit (STATE_WARNING); 1738 exit(STATE_WARNING);
1825 } else 1739 } else
1826 max_page_len = atoi(tmp); 1740 max_page_len = atoi(tmp);
1827 } else 1741 } else
1828 min_page_len = atoi (optarg); 1742 min_page_len = atoi(optarg);
1829 break; 1743 break;
1830 } 1744 }
1831 case 'N': /* no-body */ 1745 case 'N': /* no-body */
1832 no_body = true; 1746 no_body = true;
1833 break; 1747 break;
1834 case 'M': /* max-age */ 1748 case 'M': /* max-age */
1835 { 1749 {
1836 int L = strlen(optarg); 1750 int L = strlen(optarg);
1837 if (L && optarg[L-1] == 'm') 1751 if (L && optarg[L - 1] == 'm')
1838 maximum_age = atoi (optarg) * 60; 1752 maximum_age = atoi(optarg) * 60;
1839 else if (L && optarg[L-1] == 'h') 1753 else if (L && optarg[L - 1] == 'h')
1840 maximum_age = atoi (optarg) * 60 * 60; 1754 maximum_age = atoi(optarg) * 60 * 60;
1841 else if (L && optarg[L-1] == 'd') 1755 else if (L && optarg[L - 1] == 'd')
1842 maximum_age = atoi (optarg) * 60 * 60 * 24; 1756 maximum_age = atoi(optarg) * 60 * 60 * 24;
1843 else if (L && (optarg[L-1] == 's' || 1757 else if (L && (optarg[L - 1] == 's' || isdigit(optarg[L - 1])))
1844 isdigit (optarg[L-1]))) 1758 maximum_age = atoi(optarg);
1845 maximum_age = atoi (optarg); 1759 else {
1846 else { 1760 fprintf(stderr, "unparsable max-age: %s\n", optarg);
1847 fprintf (stderr, "unparsable max-age: %s\n", optarg); 1761 exit(STATE_WARNING);
1848 exit (STATE_WARNING); 1762 }
1849 } 1763 if (verbose >= 2)
1850 if (verbose >= 2) 1764 printf("* Maximal age of document set to %d seconds\n", maximum_age);
1851 printf ("* Maximal age of document set to %d seconds\n", maximum_age); 1765 } break;
1852 } 1766 case 'E': /* show extended perfdata */
1853 break; 1767 show_extended_perfdata = true;
1854 case 'E': /* show extended perfdata */ 1768 break;
1855 show_extended_perfdata = true; 1769 case 'B': /* print body content after status line */
1856 break; 1770 show_body = true;
1857 case 'B': /* print body content after status line */ 1771 break;
1858 show_body = true; 1772 case HTTP_VERSION_OPTION:
1859 break; 1773 curl_http_version = CURL_HTTP_VERSION_NONE;
1860 case HTTP_VERSION_OPTION: 1774 if (strcmp(optarg, "1.0") == 0) {
1861 curl_http_version = CURL_HTTP_VERSION_NONE; 1775 curl_http_version = CURL_HTTP_VERSION_1_0;
1862 if (strcmp (optarg, "1.0") == 0) { 1776 } else if (strcmp(optarg, "1.1") == 0) {
1863 curl_http_version = CURL_HTTP_VERSION_1_0; 1777 curl_http_version = CURL_HTTP_VERSION_1_1;
1864 } else if (strcmp (optarg, "1.1") == 0) { 1778 } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) {
1865 curl_http_version = CURL_HTTP_VERSION_1_1;
1866 } else if ((strcmp (optarg, "2.0") == 0) || (strcmp (optarg, "2") == 0)) {
1867#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) 1779#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
1868 curl_http_version = CURL_HTTP_VERSION_2_0; 1780 curl_http_version = CURL_HTTP_VERSION_2_0;
1869#else 1781#else
1870 curl_http_version = CURL_HTTP_VERSION_NONE; 1782 curl_http_version = CURL_HTTP_VERSION_NONE;
1871#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */ 1783#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
1872 } else { 1784 } else {
1873 fprintf (stderr, "unknown http-version parameter: %s\n", optarg); 1785 fprintf(stderr, "unknown http-version parameter: %s\n", optarg);
1874 exit (STATE_WARNING); 1786 exit(STATE_WARNING);
1875 } 1787 }
1876 break; 1788 break;
1877 case AUTOMATIC_DECOMPRESSION: 1789 case AUTOMATIC_DECOMPRESSION:
1878 automatic_decompression = true; 1790 automatic_decompression = true;
1879 break; 1791 break;
1880 case COOKIE_JAR: 1792 case COOKIE_JAR:
1881 cookie_jar_file = optarg; 1793 cookie_jar_file = optarg;
1882 break; 1794 break;
1883 case HAPROXY_PROTOCOL: 1795 case HAPROXY_PROTOCOL:
1884 haproxy_protocol = true; 1796 haproxy_protocol = true;
1885 break; 1797 break;
1886 case '?': 1798 case '?':
1887 /* print short usage statement if args not parsable */ 1799 /* print short usage statement if args not parsable */
1888 usage5 (); 1800 usage5();
1889 break; 1801 break;
1890 } 1802 }
1891 } 1803 }
1892 1804
1893 c = optind; 1805 c = optind;
1894 1806
1895 if (server_address == NULL && c < argc) 1807 if (server_address == NULL && c < argc)
1896 server_address = strdup (argv[c++]); 1808 server_address = strdup(argv[c++]);
1897 1809
1898 if (host_name == NULL && c < argc) 1810 if (host_name == NULL && c < argc)
1899 host_name = strdup (argv[c++]); 1811 host_name = strdup(argv[c++]);
1900 1812
1901 if (server_address == NULL) { 1813 if (server_address == NULL) {
1902 if (host_name == NULL) 1814 if (host_name == NULL)
1903 usage4 (_("You must specify a server address or host name")); 1815 usage4(_("You must specify a server address or host name"));
1904 else 1816 else
1905 server_address = strdup (host_name); 1817 server_address = strdup(host_name);
1906 } 1818 }
1907 1819
1908 set_thresholds(&thlds, warning_thresholds, critical_thresholds); 1820 set_thresholds(&thlds, warning_thresholds, critical_thresholds);
1909 1821
1910 if (critical_thresholds && thlds->critical->end>(double)socket_timeout) 1822 if (critical_thresholds && thlds->critical->end > (double)socket_timeout)
1911 socket_timeout = (int)thlds->critical->end + 1; 1823 socket_timeout = (int)thlds->critical->end + 1;
1912 if (verbose >= 2) 1824 if (verbose >= 2)
1913 printf ("* Socket timeout set to %ld seconds\n", socket_timeout); 1825 printf("* Socket timeout set to %ld seconds\n", socket_timeout);
1914 1826
1915 if (http_method == NULL) 1827 if (http_method == NULL)
1916 http_method = strdup ("GET"); 1828 http_method = strdup("GET");
1917 1829
1918 if (client_cert && !client_privkey) 1830 if (client_cert && !client_privkey)
1919 usage4 (_("If you use a client certificate you must also specify a private key file")); 1831 usage4(_("If you use a client certificate you must also specify a private key file"));
1920 1832
1921 if (virtual_port == 0) 1833 if (virtual_port == 0)
1922 virtual_port = server_port; 1834 virtual_port = server_port;
1923 else { 1835 else {
1924 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT)) 1836 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT))
1925 if(!specify_port) 1837 if (!specify_port)
1926 server_port = virtual_port; 1838 server_port = virtual_port;
1927 } 1839 }
1928 1840
1929 return true; 1841 return true;
1930} 1842}
1931 1843
1932char *perfd_time (double elapsed_time) 1844char *perfd_time(double elapsed_time) {
1933{ 1845 return fperfdata("time", elapsed_time, "s", thlds->warning ? true : false, thlds->warning ? thlds->warning->end : 0,
1934 return fperfdata ("time", elapsed_time, "s", 1846 thlds->critical ? true : false, thlds->critical ? thlds->critical->end : 0, true, 0, true, socket_timeout);
1935 thlds->warning?true:false, thlds->warning?thlds->warning->end:0,
1936 thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
1937 true, 0, true, socket_timeout);
1938} 1847}
1939 1848
1940char *perfd_time_connect (double elapsed_time_connect) 1849char *perfd_time_connect(double elapsed_time_connect) {
1941{ 1850 return fperfdata("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1942 return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1943} 1851}
1944 1852
1945char *perfd_time_ssl (double elapsed_time_ssl) 1853char *perfd_time_ssl(double elapsed_time_ssl) {
1946{ 1854 return fperfdata("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1947 return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1948} 1855}
1949 1856
1950char *perfd_time_headers (double elapsed_time_headers) 1857char *perfd_time_headers(double elapsed_time_headers) {
1951{ 1858 return fperfdata("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1952 return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1953} 1859}
1954 1860
1955char *perfd_time_firstbyte (double elapsed_time_firstbyte) 1861char *perfd_time_firstbyte(double elapsed_time_firstbyte) {
1956{ 1862 return fperfdata("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1957 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1958} 1863}
1959 1864
1960char *perfd_time_transfer (double elapsed_time_transfer) 1865char *perfd_time_transfer(double elapsed_time_transfer) {
1961{ 1866 return fperfdata("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1962 return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1963} 1867}
1964 1868
1965char *perfd_size (int page_len) 1869char *perfd_size(int page_len) {
1966{ 1870 return perfdata("size", page_len, "B", (min_page_len > 0 ? true : false), min_page_len, (min_page_len > 0 ? true : false), 0, true, 0,
1967 return perfdata ("size", page_len, "B", 1871 false, 0);
1968 (min_page_len>0?true:false), min_page_len,
1969 (min_page_len>0?true:false), 0,
1970 true, 0, false, 0);
1971} 1872}
1972 1873
1973void 1874void print_help(void) {
1974print_help (void) 1875 print_revision(progname, NP_VERSION);
1975{
1976 print_revision (progname, NP_VERSION);
1977 1876
1978 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 1877 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1979 printf (COPYRIGHT, copyright, email); 1878 printf(COPYRIGHT, copyright, email);
1980 1879
1981 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test")); 1880 printf("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1982 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for")); 1881 printf("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1983 printf ("%s\n", _("strings and regular expressions, check connection times, and report on")); 1882 printf("%s\n", _("strings and regular expressions, check connection times, and report on"));
1984 printf ("%s\n", _("certificate expiration times.")); 1883 printf("%s\n", _("certificate expiration times."));
1985 printf ("\n"); 1884 printf("\n");
1986 printf ("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http")); 1885 printf("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http"));
1987 printf ("%s\n", _("as possible.")); 1886 printf("%s\n", _("as possible."));
1988 1887
1989 printf ("\n\n"); 1888 printf("\n\n");
1990 1889
1991 print_usage (); 1890 print_usage();
1992 1891
1993 printf (_("NOTE: One or both of -H and -I must be specified")); 1892 printf(_("NOTE: One or both of -H and -I must be specified"));
1994 1893
1995 printf ("\n"); 1894 printf("\n");
1996 1895
1997 printf (UT_HELP_VRSN); 1896 printf(UT_HELP_VRSN);
1998 printf (UT_EXTRA_OPTS); 1897 printf(UT_EXTRA_OPTS);
1999 1898
2000 printf (" %s\n", "-H, --hostname=ADDRESS"); 1899 printf(" %s\n", "-H, --hostname=ADDRESS");
2001 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)")); 1900 printf(" %s\n", _("Host name argument for servers using host headers (virtual host)"));
2002 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)")); 1901 printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
2003 printf (" %s\n", "-I, --IP-address=ADDRESS"); 1902 printf(" %s\n", "-I, --IP-address=ADDRESS");
2004 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup).")); 1903 printf(" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
2005 printf (" %s\n", "-p, --port=INTEGER"); 1904 printf(" %s\n", "-p, --port=INTEGER");
2006 printf (" %s", _("Port number (default: ")); 1905 printf(" %s", _("Port number (default: "));
2007 printf ("%d)\n", HTTP_PORT); 1906 printf("%d)\n", HTTP_PORT);
2008 1907
2009 printf (UT_IPv46); 1908 printf(UT_IPv46);
2010 1909
2011#ifdef LIBCURL_FEATURE_SSL 1910#ifdef LIBCURL_FEATURE_SSL
2012 printf (" %s\n", "-S, --ssl=VERSION[+]"); 1911 printf(" %s\n", "-S, --ssl=VERSION[+]");
2013 printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents")); 1912 printf(" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
2014 printf (" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,")); 1913 printf(" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,"));
2015 printf (" %s\n", _("1.2 = TLSv1.2, 1.3 = TLSv1.3). With a '+' suffix, newer versions are also accepted.")); 1914 printf(" %s\n", _("1.2 = TLSv1.2, 1.3 = TLSv1.3). With a '+' suffix, newer versions are also accepted."));
2016 printf (" %s\n", _("Note: SSLv2 and SSLv3 are deprecated and are usually disabled in libcurl")); 1915 printf(" %s\n", _("Note: SSLv2 and SSLv3 are deprecated and are usually disabled in libcurl"));
2017 printf (" %s\n", "--sni"); 1916 printf(" %s\n", "--sni");
2018 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 1917 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
2019#if LIBCURL_VERSION_NUM >= 0x071801 1918# if LIBCURL_VERSION_NUM >= 0x071801
2020 printf (" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and")); 1919 printf(" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and"));
2021 printf (" %s\n", _(" SNI only really works since TLSv1.0")); 1920 printf(" %s\n", _(" SNI only really works since TLSv1.0"));
2022#else 1921# else
2023 printf (" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1")); 1922 printf(" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1"));
2024#endif 1923# endif
2025 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]"); 1924 printf(" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
2026 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443.")); 1925 printf(" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443."));
2027 printf (" %s\n", _("A STATE_WARNING is returned if the certificate has a validity less than the")); 1926 printf(" %s\n", _("A STATE_WARNING is returned if the certificate has a validity less than the"));
2028 printf (" %s\n", _("first agument's value. If there is a second argument and the certificate's")); 1927 printf(" %s\n", _("first agument's value. If there is a second argument and the certificate's"));
2029 printf (" %s\n", _("validity is less than its value, a STATE_CRITICAL is returned.")); 1928 printf(" %s\n", _("validity is less than its value, a STATE_CRITICAL is returned."));
2030 printf (" %s\n", _("(When this option is used the URL is not checked by default. You can use")); 1929 printf(" %s\n", _("(When this option is used the URL is not checked by default. You can use"));
2031 printf (" %s\n", _(" --continue-after-certificate to override this behavior)")); 1930 printf(" %s\n", _(" --continue-after-certificate to override this behavior)"));
2032 printf (" %s\n", "--continue-after-certificate"); 1931 printf(" %s\n", "--continue-after-certificate");
2033 printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check.")); 1932 printf(" %s\n", _("Allows the HTTP check to continue after performing the certificate check."));
2034 printf (" %s\n", _("Does nothing unless -C is used.")); 1933 printf(" %s\n", _("Does nothing unless -C is used."));
2035 printf (" %s\n", "-J, --client-cert=FILE"); 1934 printf(" %s\n", "-J, --client-cert=FILE");
2036 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)")); 1935 printf(" %s\n", _("Name of file that contains the client certificate (PEM format)"));
2037 printf (" %s\n", _("to be used in establishing the SSL session")); 1936 printf(" %s\n", _("to be used in establishing the SSL session"));
2038 printf (" %s\n", "-K, --private-key=FILE"); 1937 printf(" %s\n", "-K, --private-key=FILE");
2039 printf (" %s\n", _("Name of file containing the private key (PEM format)")); 1938 printf(" %s\n", _("Name of file containing the private key (PEM format)"));
2040 printf (" %s\n", _("matching the client certificate")); 1939 printf(" %s\n", _("matching the client certificate"));
2041 printf (" %s\n", "--ca-cert=FILE"); 1940 printf(" %s\n", "--ca-cert=FILE");
2042 printf (" %s\n", _("CA certificate file to verify peer against")); 1941 printf(" %s\n", _("CA certificate file to verify peer against"));
2043 printf (" %s\n", "-D, --verify-cert"); 1942 printf(" %s\n", "-D, --verify-cert");
2044 printf (" %s\n", _("Verify the peer's SSL certificate and hostname")); 1943 printf(" %s\n", _("Verify the peer's SSL certificate and hostname"));
2045#endif 1944#endif
2046 1945
2047 printf (" %s\n", "-e, --expect=STRING"); 1946 printf(" %s\n", "-e, --expect=STRING");
2048 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in")); 1947 printf(" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
2049 printf (" %s", _("the first (status) line of the server response (default: ")); 1948 printf(" %s", _("the first (status) line of the server response (default: "));
2050 printf ("%s)\n", HTTP_EXPECT); 1949 printf("%s)\n", HTTP_EXPECT);
2051 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)")); 1950 printf(" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
2052 printf (" %s\n", "-d, --header-string=STRING"); 1951 printf(" %s\n", "-d, --header-string=STRING");
2053 printf (" %s\n", _("String to expect in the response headers")); 1952 printf(" %s\n", _("String to expect in the response headers"));
2054 printf (" %s\n", "-s, --string=STRING"); 1953 printf(" %s\n", "-s, --string=STRING");
2055 printf (" %s\n", _("String to expect in the content")); 1954 printf(" %s\n", _("String to expect in the content"));
2056 printf (" %s\n", "-u, --url=PATH"); 1955 printf(" %s\n", "-u, --url=PATH");
2057 printf (" %s\n", _("URL to GET or POST (default: /)")); 1956 printf(" %s\n", _("URL to GET or POST (default: /)"));
2058 printf (" %s\n", "-P, --post=STRING"); 1957 printf(" %s\n", "-P, --post=STRING");
2059 printf (" %s\n", _("URL decoded http POST data")); 1958 printf(" %s\n", _("URL decoded http POST data"));
2060 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)"); 1959 printf(" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)");
2061 printf (" %s\n", _("Set HTTP method.")); 1960 printf(" %s\n", _("Set HTTP method."));
2062 printf (" %s\n", "-N, --no-body"); 1961 printf(" %s\n", "-N, --no-body");
2063 printf (" %s\n", _("Don't wait for document body: stop reading after headers.")); 1962 printf(" %s\n", _("Don't wait for document body: stop reading after headers."));
2064 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)")); 1963 printf(" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
2065 printf (" %s\n", "-M, --max-age=SECONDS"); 1964 printf(" %s\n", "-M, --max-age=SECONDS");
2066 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of")); 1965 printf(" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
2067 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.")); 1966 printf(" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
2068 printf (" %s\n", "-T, --content-type=STRING"); 1967 printf(" %s\n", "-T, --content-type=STRING");
2069 printf (" %s\n", _("specify Content-Type header media type when POSTing\n")); 1968 printf(" %s\n", _("specify Content-Type header media type when POSTing\n"));
2070 printf (" %s\n", "-l, --linespan"); 1969 printf(" %s\n", "-l, --linespan");
2071 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)")); 1970 printf(" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
2072 printf (" %s\n", "-r, --regex, --ereg=STRING"); 1971 printf(" %s\n", "-r, --regex, --ereg=STRING");
2073 printf (" %s\n", _("Search page for regex STRING")); 1972 printf(" %s\n", _("Search page for regex STRING"));
2074 printf (" %s\n", "-R, --eregi=STRING"); 1973 printf(" %s\n", "-R, --eregi=STRING");
2075 printf (" %s\n", _("Search page for case-insensitive regex STRING")); 1974 printf(" %s\n", _("Search page for case-insensitive regex STRING"));
2076 printf (" %s\n", "--invert-regex"); 1975 printf(" %s\n", "--invert-regex");
2077 printf (" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)")); 1976 printf(" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)"));
2078 printf (" %s\n", _("can be changed with --state--regex)")); 1977 printf(" %s\n", _("can be changed with --state--regex)"));
2079 printf (" %s\n", "--state-regex=STATE"); 1978 printf(" %s\n", "--state-regex=STATE");
2080 printf (" %s\n", _("Return STATE if regex is found, OK if not. STATE can be one of \"critical\",\"warning\"")); 1979 printf(" %s\n", _("Return STATE if regex is found, OK if not. STATE can be one of \"critical\",\"warning\""));
2081 printf (" %s\n", "-a, --authorization=AUTH_PAIR"); 1980 printf(" %s\n", "-a, --authorization=AUTH_PAIR");
2082 printf (" %s\n", _("Username:password on sites with basic authentication")); 1981 printf(" %s\n", _("Username:password on sites with basic authentication"));
2083 printf (" %s\n", "-b, --proxy-authorization=AUTH_PAIR"); 1982 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
2084 printf (" %s\n", _("Username:password on proxy-servers with basic authentication")); 1983 printf(" %s\n", _("Username:password on proxy-servers with basic authentication"));
2085 printf (" %s\n", "-A, --useragent=STRING"); 1984 printf(" %s\n", "-A, --useragent=STRING");
2086 printf (" %s\n", _("String to be sent in http header as \"User Agent\"")); 1985 printf(" %s\n", _("String to be sent in http header as \"User Agent\""));
2087 printf (" %s\n", "-k, --header=STRING"); 1986 printf(" %s\n", "-k, --header=STRING");
2088 printf (" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers")); 1987 printf(" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers"));
2089 printf (" %s\n", "-E, --extended-perfdata"); 1988 printf(" %s\n", "-E, --extended-perfdata");
2090 printf (" %s\n", _("Print additional performance data")); 1989 printf(" %s\n", _("Print additional performance data"));
2091 printf (" %s\n", "-B, --show-body"); 1990 printf(" %s\n", "-B, --show-body");
2092 printf (" %s\n", _("Print body content below status line")); 1991 printf(" %s\n", _("Print body content below status line"));
2093 printf (" %s\n", "-L, --link"); 1992 printf(" %s\n", "-L, --link");
2094 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)")); 1993 printf(" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
2095 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport|curl>"); 1994 printf(" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport|curl>");
2096 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the")); 1995 printf(" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
2097 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same.")); 1996 printf(" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
2098 printf (" %s\n", _("follow uses the old redirection algorithm of check_http.")); 1997 printf(" %s\n", _("follow uses the old redirection algorithm of check_http."));
2099 printf (" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl.")); 1998 printf(" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl."));
2100 printf (" %s\n", "--max-redirs=INTEGER"); 1999 printf(" %s\n", "--max-redirs=INTEGER");
2101 printf (" %s", _("Maximal number of redirects (default: ")); 2000 printf(" %s", _("Maximal number of redirects (default: "));
2102 printf ("%d)\n", DEFAULT_MAX_REDIRS); 2001 printf("%d)\n", DEFAULT_MAX_REDIRS);
2103 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); 2002 printf(" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
2104 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); 2003 printf(" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
2105 printf ("\n"); 2004 printf("\n");
2106 printf (" %s\n", "--http-version=VERSION"); 2005 printf(" %s\n", "--http-version=VERSION");
2107 printf (" %s\n", _("Connect via specific HTTP protocol.")); 2006 printf(" %s\n", _("Connect via specific HTTP protocol."));
2108 printf (" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)")); 2007 printf(" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)"));
2109 printf (" %s\n", "--enable-automatic-decompression"); 2008 printf(" %s\n", "--enable-automatic-decompression");
2110 printf (" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING).")); 2009 printf(" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING)."));
2111 printf(" %s\n", "--haproxy-protocol"); 2010 printf(" %s\n", "--haproxy-protocol");
2112 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL).")); 2011 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL)."));
2113 printf (" %s\n", "--cookie-jar=FILE"); 2012 printf(" %s\n", "--cookie-jar=FILE");
2114 printf (" %s\n", _("Store cookies in the cookie jar and send them out when requested.")); 2013 printf(" %s\n", _("Store cookies in the cookie jar and send them out when requested."));
2115 printf ("\n"); 2014 printf("\n");
2116 2015
2117 printf (UT_WARN_CRIT); 2016 printf(UT_WARN_CRIT);
2118 2017
2119 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 2018 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
2120 2019
2121 printf (UT_VERBOSE); 2020 printf(UT_VERBOSE);
2122 2021
2123 printf ("\n"); 2022 printf("\n");
2124 printf ("%s\n", _("Notes:")); 2023 printf("%s\n", _("Notes:"));
2125 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host.")); 2024 printf(" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
2126 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL")); 2025 printf(" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
2127 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response")); 2026 printf(" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response"));
2128 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are")); 2027 printf(" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
2129 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN")); 2028 printf(" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
2130 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument.")); 2029 printf(" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
2131 2030
2132#ifdef LIBCURL_FEATURE_SSL 2031#ifdef LIBCURL_FEATURE_SSL
2133 printf ("\n"); 2032 printf("\n");
2134 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to")); 2033 printf(" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
2135 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 ")); 2034 printf(" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
2136 printf (" %s\n", _("certificate is still valid for the specified number of days.")); 2035 printf(" %s\n", _("certificate is still valid for the specified number of days."));
2137 printf ("\n"); 2036 printf("\n");
2138 printf (" %s\n", _("Please note that this plugin does not check if the presented server")); 2037 printf(" %s\n", _("Please note that this plugin does not check if the presented server"));
2139 printf (" %s\n", _("certificate matches the hostname of the server, or if the certificate")); 2038 printf(" %s\n", _("certificate matches the hostname of the server, or if the certificate"));
2140 printf (" %s\n", _("has a valid chain of trust to one of the locally installed CAs.")); 2039 printf(" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
2141 printf ("\n"); 2040 printf("\n");
2142 printf ("%s\n", _("Examples:")); 2041 printf("%s\n", _("Examples:"));
2143 printf (" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com"); 2042 printf(" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com");
2144 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,")); 2043 printf(" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
2145 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 2044 printf(" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
2146 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 2045 printf(" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
2147 printf (" %s\n", _("a STATE_CRITICAL will be returned.")); 2046 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
2148 printf ("\n"); 2047 printf("\n");
2149 printf (" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14"); 2048 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14");
2150 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,")); 2049 printf(" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
2151 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 2050 printf(" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
2152 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when")); 2051 printf(" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
2153 printf (" %s\n\n", _("the certificate is expired.")); 2052 printf(" %s\n\n", _("the certificate is expired."));
2154 printf ("\n"); 2053 printf("\n");
2155 printf (" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14"); 2054 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14");
2156 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,")); 2055 printf(" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,"));
2157 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 2056 printf(" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
2158 printf (" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned.")); 2057 printf(" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned."));
2159 printf (" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days")); 2058 printf(" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
2160#endif 2059#endif
2161 2060
2162 printf ("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:"); 2061 printf("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:");
2163 printf (" %s\n", _("It is recommended to use an environment proxy like:")); 2062 printf(" %s\n", _("It is recommended to use an environment proxy like:"));
2164 printf (" %s\n", _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org")); 2063 printf(" %s\n", _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org"));
2165 printf (" %s\n", _("legacy proxy requests in check_http style still work:")); 2064 printf(" %s\n", _("legacy proxy requests in check_http style still work:"));
2166 printf (" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ -H www.monitoring-plugins.org")); 2065 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ -H www.monitoring-plugins.org"));
2167 2066
2168#ifdef LIBCURL_FEATURE_SSL 2067#ifdef LIBCURL_FEATURE_SSL
2169 printf ("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: "); 2068 printf("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: ");
2170 printf (" %s\n", _("It is recommended to use an environment proxy like:")); 2069 printf(" %s\n", _("It is recommended to use an environment proxy like:"));
2171 printf (" %s\n", _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S")); 2070 printf(" %s\n", _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S"));
2172 printf (" %s\n", _("legacy proxy requests in check_http style still work:")); 2071 printf(" %s\n", _("legacy proxy requests in check_http style still work:"));
2173 printf (" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com ")); 2072 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com "));
2174 printf (" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>")); 2073 printf(" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>"));
2175 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 2074 printf(" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
2176 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 2075 printf(" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
2177 printf (" %s\n", _("a STATE_CRITICAL will be returned.")); 2076 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
2178 2077
2179#endif 2078#endif
2180 2079
2181 printf (UT_SUPPORT); 2080 printf(UT_SUPPORT);
2182
2183} 2081}
2184 2082
2185 2083void print_usage(void) {
2186 2084 printf("%s\n", _("Usage:"));
2187void 2085 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname);
2188print_usage (void) 2086 printf(" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n");
2189{ 2087 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
2190 printf ("%s\n", _("Usage:")); 2088 printf(" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n");
2191 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname); 2089 printf(" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
2192 printf (" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n"); 2090 printf(" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
2193 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); 2091 printf(" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n");
2194 printf (" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n"); 2092 printf(" [-T <content-type>] [-j method]\n");
2195 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); 2093 printf(" [--http-version=<version>] [--enable-automatic-decompression]\n");
2196 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); 2094 printf(" [--cookie-jar=<cookie jar file>\n");
2197 printf (" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n"); 2095 printf(" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n", progname);
2198 printf (" [-T <content-type>] [-j method]\n"); 2096 printf(" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
2199 printf (" [--http-version=<version>] [--enable-automatic-decompression]\n"); 2097 printf("\n");
2200 printf (" [--cookie-jar=<cookie jar file>\n");
2201 printf (" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n",progname);
2202 printf (" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
2203 printf ("\n");
2204#ifdef LIBCURL_FEATURE_SSL 2098#ifdef LIBCURL_FEATURE_SSL
2205 printf ("%s\n", _("In the first form, make an HTTP request.")); 2099 printf("%s\n", _("In the first form, make an HTTP request."));
2206 printf ("%s\n\n", _("In the second form, connect to the server and check the TLS certificate.")); 2100 printf("%s\n\n", _("In the second form, connect to the server and check the TLS certificate."));
2207#endif 2101#endif
2208} 2102}
2209 2103
2210void 2104void print_curl_version(void) { printf("%s\n", curl_version()); }
2211print_curl_version (void)
2212{
2213 printf( "%s\n", curl_version());
2214}
2215 2105
2216int 2106int curlhelp_initwritebuffer(curlhelp_write_curlbuf *buf) {
2217curlhelp_initwritebuffer (curlhelp_write_curlbuf *buf) 2107 buf->bufsize = DEFAULT_BUFFER_SIZE;
2218{ 2108 buf->buflen = 0;
2219 buf->bufsize = DEFAULT_BUFFER_SIZE; 2109 buf->buf = (char *)malloc((size_t)buf->bufsize);
2220 buf->buflen = 0; 2110 if (buf->buf == NULL)
2221 buf->buf = (char *)malloc ((size_t)buf->bufsize); 2111 return -1;
2222 if (buf->buf == NULL) return -1; 2112 return 0;
2223 return 0;
2224} 2113}
2225 2114
2226size_t curlhelp_buffer_write_callback (void *buffer, size_t size, size_t nmemb, void *stream) 2115size_t curlhelp_buffer_write_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
2227{ 2116 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
2228 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
2229 2117
2230 while (buf->bufsize < buf->buflen + size * nmemb + 1) { 2118 while (buf->bufsize < buf->buflen + size * nmemb + 1) {
2231 buf->bufsize = buf->bufsize * 2; 2119 buf->bufsize = buf->bufsize * 2;
2232 buf->buf = (char *)realloc (buf->buf, buf->bufsize); 2120 buf->buf = (char *)realloc(buf->buf, buf->bufsize);
2233 if (buf->buf == NULL) { 2121 if (buf->buf == NULL) {
2234 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno)); 2122 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno));
2235 return -1; 2123 return -1;
2236 } 2124 }
2237 } 2125 }
2238 2126
2239 memcpy (buf->buf + buf->buflen, buffer, size * nmemb); 2127 memcpy(buf->buf + buf->buflen, buffer, size * nmemb);
2240 buf->buflen += size * nmemb; 2128 buf->buflen += size * nmemb;
2241 buf->buf[buf->buflen] = '\0'; 2129 buf->buf[buf->buflen] = '\0';
2242 2130
2243 return (int)(size * nmemb); 2131 return (int)(size * nmemb);
2244} 2132}
2245 2133
2246size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) 2134size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
2247{ 2135 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
2248 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
2249 2136
2250 size_t n = min (nmemb * size, buf->buflen - buf->pos); 2137 size_t n = min(nmemb * size, buf->buflen - buf->pos);
2251 2138
2252 memcpy (buffer, buf->buf + buf->pos, n); 2139 memcpy(buffer, buf->buf + buf->pos, n);
2253 buf->pos += n; 2140 buf->pos += n;
2254 2141
2255 return (int)n; 2142 return (int)n;
2256} 2143}
2257 2144
2258void 2145void curlhelp_freewritebuffer(curlhelp_write_curlbuf *buf) {
2259curlhelp_freewritebuffer (curlhelp_write_curlbuf *buf) 2146 free(buf->buf);
2260{ 2147 buf->buf = NULL;
2261 free (buf->buf);
2262 buf->buf = NULL;
2263} 2148}
2264 2149
2265int 2150int curlhelp_initreadbuffer(curlhelp_read_curlbuf *buf, const char *data, size_t datalen) {
2266curlhelp_initreadbuffer (curlhelp_read_curlbuf *buf, const char *data, size_t datalen) 2151 buf->buflen = datalen;
2267{ 2152 buf->buf = (char *)malloc((size_t)buf->buflen);
2268 buf->buflen = datalen; 2153 if (buf->buf == NULL)
2269 buf->buf = (char *)malloc ((size_t)buf->buflen); 2154 return -1;
2270 if (buf->buf == NULL) return -1; 2155 memcpy(buf->buf, data, datalen);
2271 memcpy (buf->buf, data, datalen); 2156 buf->pos = 0;
2272 buf->pos = 0; 2157 return 0;
2273 return 0;
2274} 2158}
2275 2159
2276void 2160void curlhelp_freereadbuffer(curlhelp_read_curlbuf *buf) {
2277curlhelp_freereadbuffer (curlhelp_read_curlbuf *buf) 2161 free(buf->buf);
2278{ 2162 buf->buf = NULL;
2279 free (buf->buf);
2280 buf->buf = NULL;
2281} 2163}
2282 2164
2283/* TODO: where to put this, it's actually part of sstrings2 (logically)? 2165/* TODO: where to put this, it's actually part of sstrings2 (logically)?
2284 */ 2166 */
2285const char* 2167const char *strrstr2(const char *haystack, const char *needle) {
2286strrstr2(const char *haystack, const char *needle) 2168 int counter;
2287{ 2169 size_t len;
2288 int counter; 2170 const char *prev_pos;
2289 size_t len; 2171 const char *pos;
2290 const char *prev_pos; 2172
2291 const char *pos; 2173 if (haystack == NULL || needle == NULL)
2292 2174 return NULL;
2293 if (haystack == NULL || needle == NULL) 2175
2294 return NULL; 2176 if (haystack[0] == '\0' || needle[0] == '\0')
2295 2177 return NULL;
2296 if (haystack[0] == '\0' || needle[0] == '\0') 2178
2297 return NULL; 2179 counter = 0;
2298 2180 prev_pos = NULL;
2299 counter = 0; 2181 pos = haystack;
2300 prev_pos = NULL; 2182 len = strlen(needle);
2301 pos = haystack; 2183 for (;;) {
2302 len = strlen (needle); 2184 pos = strstr(pos, needle);
2303 for (;;) { 2185 if (pos == NULL) {
2304 pos = strstr (pos, needle); 2186 if (counter == 0)
2305 if (pos == NULL) { 2187 return NULL;
2306 if (counter == 0) 2188 return prev_pos;
2307 return NULL; 2189 }
2308 else 2190 counter++;
2309 return prev_pos; 2191 prev_pos = pos;
2310 } 2192 pos += len;
2311 counter++; 2193 if (*pos == '\0')
2312 prev_pos = pos; 2194 return prev_pos;
2313 pos += len; 2195 }
2314 if (*pos == '\0') return prev_pos;
2315 }
2316} 2196}
2317 2197
2318int 2198int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) {
2319curlhelp_parse_statusline (const char *buf, curlhelp_statusline *status_line) 2199 char *first_line_end;
2320{ 2200 char *p;
2321 char *first_line_end; 2201 size_t first_line_len;
2322 char *p; 2202 char *pp;
2323 size_t first_line_len; 2203 const char *start;
2324 char *pp; 2204 char *first_line_buf;
2325 const char *start; 2205
2326 char *first_line_buf; 2206 /* find last start of a new header */
2327 2207 start = strrstr2(buf, "\r\nHTTP/");
2328 /* find last start of a new header */ 2208 if (start != NULL) {
2329 start = strrstr2 (buf, "\r\nHTTP/"); 2209 start += 2;
2330 if (start != NULL) { 2210 buf = start;
2331 start += 2; 2211 }
2332 buf = start;
2333 }
2334
2335 first_line_end = strstr(buf, "\r\n");
2336 if (first_line_end == NULL) return -1;
2337
2338 first_line_len = (size_t)(first_line_end - buf);
2339 status_line->first_line = (char *)malloc (first_line_len + 1);
2340 if (status_line->first_line == NULL) return -1;
2341 memcpy (status_line->first_line, buf, first_line_len);
2342 status_line->first_line[first_line_len] = '\0';
2343 first_line_buf = strdup( status_line->first_line );
2344
2345 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
2346
2347 p = strtok(first_line_buf, "/");
2348 if( p == NULL ) { free( first_line_buf ); return -1; }
2349 if( strcmp( p, "HTTP" ) != 0 ) { free( first_line_buf ); return -1; }
2350
2351 p = strtok( NULL, " " );
2352 if( p == NULL ) { free( first_line_buf ); return -1; }
2353 if( strchr( p, '.' ) != NULL ) {
2354
2355 /* HTTP 1.x case */
2356 strtok( p, "." );
2357 status_line->http_major = (int)strtol( p, &pp, 10 );
2358 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2359 strtok( NULL, " " );
2360 status_line->http_minor = (int)strtol( p, &pp, 10 );
2361 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2362 p += 4; /* 1.x SP */
2363 } else {
2364 /* HTTP 2 case */
2365 status_line->http_major = (int)strtol( p, &pp, 10 );
2366 status_line->http_minor = 0;
2367 p += 2; /* 2 SP */
2368 }
2369
2370 /* status code: "404" or "404.1", then SP */
2371
2372 p = strtok( p, " " );
2373 if( p == NULL ) { free( first_line_buf ); return -1; }
2374 if( strchr( p, '.' ) != NULL ) {
2375 char *ppp;
2376 ppp = strtok( p, "." );
2377 status_line->http_code = (int)strtol( ppp, &pp, 10 );
2378 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2379 ppp = strtok( NULL, "" );
2380 status_line->http_subcode = (int)strtol( ppp, &pp, 10 );
2381 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2382 p += 6; /* 400.1 SP */
2383 } else {
2384 status_line->http_code = (int)strtol( p, &pp, 10 );
2385 status_line->http_subcode = -1;
2386 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2387 p += 4; /* 400 SP */
2388 }
2389
2390 /* Human readable message: "Not Found" CRLF */
2391
2392 p = strtok( p, "" );
2393 if( p == NULL ) { status_line->msg = ""; return 0; }
2394 status_line->msg = status_line->first_line + ( p - first_line_buf );
2395 free( first_line_buf );
2396
2397 return 0;
2398}
2399 2212
2400void 2213 first_line_end = strstr(buf, "\r\n");
2401curlhelp_free_statusline (curlhelp_statusline *status_line) 2214 if (first_line_end == NULL)
2402{ 2215 return -1;
2403 free (status_line->first_line); 2216
2404} 2217 first_line_len = (size_t)(first_line_end - buf);
2218 status_line->first_line = (char *)malloc(first_line_len + 1);
2219 if (status_line->first_line == NULL)
2220 return -1;
2221 memcpy(status_line->first_line, buf, first_line_len);
2222 status_line->first_line[first_line_len] = '\0';
2223 first_line_buf = strdup(status_line->first_line);
2224
2225 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
2226
2227 p = strtok(first_line_buf, "/");
2228 if (p == NULL) {
2229 free(first_line_buf);
2230 return -1;
2231 }
2232 if (strcmp(p, "HTTP") != 0) {
2233 free(first_line_buf);
2234 return -1;
2235 }
2236
2237 p = strtok(NULL, " ");
2238 if (p == NULL) {
2239 free(first_line_buf);
2240 return -1;
2241 }
2242 if (strchr(p, '.') != NULL) {
2243
2244 /* HTTP 1.x case */
2245 strtok(p, ".");
2246 status_line->http_major = (int)strtol(p, &pp, 10);
2247 if (*pp != '\0') {
2248 free(first_line_buf);
2249 return -1;
2250 }
2251 strtok(NULL, " ");
2252 status_line->http_minor = (int)strtol(p, &pp, 10);
2253 if (*pp != '\0') {
2254 free(first_line_buf);
2255 return -1;
2256 }
2257 p += 4; /* 1.x SP */
2258 } else {
2259 /* HTTP 2 case */
2260 status_line->http_major = (int)strtol(p, &pp, 10);
2261 status_line->http_minor = 0;
2262 p += 2; /* 2 SP */
2263 }
2405 2264
2406void 2265 /* status code: "404" or "404.1", then SP */
2407remove_newlines (char *s)
2408{
2409 char *p;
2410 2266
2411 for (p = s; *p != '\0'; p++) 2267 p = strtok(p, " ");
2412 if (*p == '\r' || *p == '\n') 2268 if (p == NULL) {
2413 *p = ' '; 2269 free(first_line_buf);
2270 return -1;
2271 }
2272 if (strchr(p, '.') != NULL) {
2273 char *ppp;
2274 ppp = strtok(p, ".");
2275 status_line->http_code = (int)strtol(ppp, &pp, 10);
2276 if (*pp != '\0') {
2277 free(first_line_buf);
2278 return -1;
2279 }
2280 ppp = strtok(NULL, "");
2281 status_line->http_subcode = (int)strtol(ppp, &pp, 10);
2282 if (*pp != '\0') {
2283 free(first_line_buf);
2284 return -1;
2285 }
2286 p += 6; /* 400.1 SP */
2287 } else {
2288 status_line->http_code = (int)strtol(p, &pp, 10);
2289 status_line->http_subcode = -1;
2290 if (*pp != '\0') {
2291 free(first_line_buf);
2292 return -1;
2293 }
2294 p += 4; /* 400 SP */
2295 }
2296
2297 /* Human readable message: "Not Found" CRLF */
2298
2299 p = strtok(p, "");
2300 if (p == NULL) {
2301 status_line->msg = "";
2302 return 0;
2303 }
2304 status_line->msg = status_line->first_line + (p - first_line_buf);
2305 free(first_line_buf);
2306
2307 return 0;
2414} 2308}
2415 2309
2416char * 2310void curlhelp_free_statusline(curlhelp_statusline *status_line) { free(status_line->first_line); }
2417get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header) 2311
2418{ 2312char *get_header_value(const struct phr_header *headers, const size_t nof_headers, const char *header) {
2419 for(size_t i = 0; i < nof_headers; i++ ) { 2313 for (size_t i = 0; i < nof_headers; i++) {
2420 if(headers[i].name != NULL && strncasecmp( header, headers[i].name, max( headers[i].name_len, 4 ) ) == 0 ) { 2314 if (headers[i].name != NULL && strncasecmp(header, headers[i].name, max(headers[i].name_len, 4)) == 0) {
2421 return strndup( headers[i].value, headers[i].value_len ); 2315 return strndup(headers[i].value, headers[i].value_len);
2422 } 2316 }
2423 } 2317 }
2424 return NULL; 2318 return NULL;
2425} 2319}
2426 2320
2427int 2321int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE]) {
2428check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE]) 2322 char *server_date = NULL;
2429{ 2323 char *document_date = NULL;
2430 char *server_date = NULL; 2324 int date_result = STATE_OK;
2431 char *document_date = NULL; 2325 curlhelp_statusline status_line;
2432 int date_result = STATE_OK; 2326 struct phr_header headers[255];
2433 curlhelp_statusline status_line; 2327 size_t nof_headers = 255;
2434 struct phr_header headers[255]; 2328 size_t msglen;
2435 size_t nof_headers = 255; 2329
2436 size_t msglen; 2330 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
2437 2331 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
2438 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
2439 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
2440 headers, &nof_headers, 0);
2441 2332
2442 if (res == -1) { 2333 if (res == -1) {
2443 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2334 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2444 } 2335 }
2445 2336
2446 server_date = get_header_value (headers, nof_headers, "date"); 2337 server_date = get_header_value(headers, nof_headers, "date");
2447 document_date = get_header_value (headers, nof_headers, "last-modified"); 2338 document_date = get_header_value(headers, nof_headers, "last-modified");
2448 2339
2449 if (!server_date || !*server_date) { 2340 if (!server_date || !*server_date) {
2450 char tmp[DEFAULT_BUFFER_SIZE]; 2341 char tmp[DEFAULT_BUFFER_SIZE];
2451 2342
2452 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg); 2343 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg);
2453 strcpy(*msg, tmp); 2344 strcpy(*msg, tmp);
2454 2345
2455 date_result = max_state_alt(STATE_UNKNOWN, date_result); 2346 date_result = max_state_alt(STATE_UNKNOWN, date_result);
@@ -2457,34 +2348,34 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
2457 } else if (!document_date || !*document_date) { 2348 } else if (!document_date || !*document_date) {
2458 char tmp[DEFAULT_BUFFER_SIZE]; 2349 char tmp[DEFAULT_BUFFER_SIZE];
2459 2350
2460 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg); 2351 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg);
2461 strcpy(*msg, tmp); 2352 strcpy(*msg, tmp);
2462 2353
2463 date_result = max_state_alt(STATE_CRITICAL, date_result); 2354 date_result = max_state_alt(STATE_CRITICAL, date_result);
2464 2355
2465 } else { 2356 } else {
2466 time_t srv_data = curl_getdate (server_date, NULL); 2357 time_t srv_data = curl_getdate(server_date, NULL);
2467 time_t doc_data = curl_getdate (document_date, NULL); 2358 time_t doc_data = curl_getdate(document_date, NULL);
2468 if (verbose >= 2) 2359 if (verbose >= 2)
2469 printf ("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data); 2360 printf("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data);
2470 if (srv_data <= 0) { 2361 if (srv_data <= 0) {
2471 char tmp[DEFAULT_BUFFER_SIZE]; 2362 char tmp[DEFAULT_BUFFER_SIZE];
2472 2363
2473 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date); 2364 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
2474 strcpy(*msg, tmp); 2365 strcpy(*msg, tmp);
2475 2366
2476 date_result = max_state_alt(STATE_CRITICAL, date_result); 2367 date_result = max_state_alt(STATE_CRITICAL, date_result);
2477 } else if (doc_data <= 0) { 2368 } else if (doc_data <= 0) {
2478 char tmp[DEFAULT_BUFFER_SIZE]; 2369 char tmp[DEFAULT_BUFFER_SIZE];
2479 2370
2480 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date); 2371 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
2481 strcpy(*msg, tmp); 2372 strcpy(*msg, tmp);
2482 2373
2483 date_result = max_state_alt(STATE_CRITICAL, date_result); 2374 date_result = max_state_alt(STATE_CRITICAL, date_result);
2484 } else if (doc_data > srv_data + 30) { 2375 } else if (doc_data > srv_data + 30) {
2485 char tmp[DEFAULT_BUFFER_SIZE]; 2376 char tmp[DEFAULT_BUFFER_SIZE];
2486 2377
2487 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data); 2378 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data);
2488 strcpy(*msg, tmp); 2379 strcpy(*msg, tmp);
2489 2380
2490 date_result = max_state_alt(STATE_CRITICAL, date_result); 2381 date_result = max_state_alt(STATE_CRITICAL, date_result);
@@ -2493,14 +2384,14 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
2493 if (n > (60 * 60 * 24 * 2)) { 2384 if (n > (60 * 60 * 24 * 2)) {
2494 char tmp[DEFAULT_BUFFER_SIZE]; 2385 char tmp[DEFAULT_BUFFER_SIZE];
2495 2386
2496 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24)); 2387 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float)n) / (60 * 60 * 24));
2497 strcpy(*msg, tmp); 2388 strcpy(*msg, tmp);
2498 2389
2499 date_result = max_state_alt(STATE_CRITICAL, date_result); 2390 date_result = max_state_alt(STATE_CRITICAL, date_result);
2500 } else { 2391 } else {
2501 char tmp[DEFAULT_BUFFER_SIZE]; 2392 char tmp[DEFAULT_BUFFER_SIZE];
2502 2393
2503 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60); 2394 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60);
2504 strcpy(*msg, tmp); 2395 strcpy(*msg, tmp);
2505 2396
2506 date_result = max_state_alt(STATE_CRITICAL, date_result); 2397 date_result = max_state_alt(STATE_CRITICAL, date_result);
@@ -2508,132 +2399,128 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
2508 } 2399 }
2509 } 2400 }
2510 2401
2511 if (server_date) free (server_date); 2402 if (server_date)
2512 if (document_date) free (document_date); 2403 free(server_date);
2404 if (document_date)
2405 free(document_date);
2513 2406
2514 return date_result; 2407 return date_result;
2515} 2408}
2516 2409
2410int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf) {
2411 size_t content_length = 0;
2412 struct phr_header headers[255];
2413 size_t nof_headers = 255;
2414 size_t msglen;
2415 char *content_length_s = NULL;
2416 curlhelp_statusline status_line;
2517 2417
2518int 2418 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
2519get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_write_curlbuf* body_buf) 2419 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
2520{
2521 size_t content_length = 0;
2522 struct phr_header headers[255];
2523 size_t nof_headers = 255;
2524 size_t msglen;
2525 char *content_length_s = NULL;
2526 curlhelp_statusline status_line;
2527
2528 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
2529 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
2530 headers, &nof_headers, 0);
2531 2420
2532 if (res == -1) { 2421 if (res == -1) {
2533 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2422 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2534 } 2423 }
2535 2424
2536 content_length_s = get_header_value (headers, nof_headers, "content-length"); 2425 content_length_s = get_header_value(headers, nof_headers, "content-length");
2537 if (!content_length_s) { 2426 if (!content_length_s) {
2538 return header_buf->buflen + body_buf->buflen; 2427 return header_buf->buflen + body_buf->buflen;
2539 } 2428 }
2540 content_length_s += strspn (content_length_s, " \t"); 2429 content_length_s += strspn(content_length_s, " \t");
2541 content_length = atoi (content_length_s); 2430 content_length = atoi(content_length_s);
2542 if (content_length != body_buf->buflen) { 2431 if (content_length != body_buf->buflen) {
2543 /* TODO: should we warn if the actual and the reported body length don't match? */ 2432 /* TODO: should we warn if the actual and the reported body length don't match? */
2544 } 2433 }
2545 2434
2546 if (content_length_s) free (content_length_s); 2435 if (content_length_s)
2436 free(content_length_s);
2547 2437
2548 return header_buf->buflen + body_buf->buflen; 2438 return header_buf->buflen + body_buf->buflen;
2549} 2439}
2550 2440
2551/* TODO: is there a better way in libcurl to check for the SSL library? */ 2441/* TODO: is there a better way in libcurl to check for the SSL library? */
2552curlhelp_ssl_library 2442curlhelp_ssl_library curlhelp_get_ssl_library(void) {
2553curlhelp_get_ssl_library () 2443 curl_version_info_data *version_data;
2554{ 2444 char *ssl_version;
2555 curl_version_info_data* version_data; 2445 char *library;
2556 char *ssl_version; 2446 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
2557 char *library; 2447
2558 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; 2448 version_data = curl_version_info(CURLVERSION_NOW);
2559 2449 if (version_data == NULL)
2560 version_data = curl_version_info (CURLVERSION_NOW); 2450 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2561 if (version_data == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN; 2451
2562 2452 ssl_version = strdup(version_data->ssl_version);
2563 ssl_version = strdup (version_data->ssl_version); 2453 if (ssl_version == NULL)
2564 if (ssl_version == NULL ) return CURLHELP_SSL_LIBRARY_UNKNOWN; 2454 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2565 2455
2566 library = strtok (ssl_version, "/"); 2456 library = strtok(ssl_version, "/");
2567 if (library == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN; 2457 if (library == NULL)
2568 2458 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2569 if (strcmp (library, "OpenSSL") == 0) 2459
2570 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL; 2460 if (strcmp(library, "OpenSSL") == 0)
2571 else if (strcmp (library, "LibreSSL") == 0) 2461 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL;
2572 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL; 2462 else if (strcmp(library, "LibreSSL") == 0)
2573 else if (strcmp (library, "GnuTLS") == 0) 2463 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL;
2574 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS; 2464 else if (strcmp(library, "GnuTLS") == 0)
2575 else if (strcmp (library, "NSS") == 0) 2465 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS;
2576 ssl_library = CURLHELP_SSL_LIBRARY_NSS; 2466 else if (strcmp(library, "NSS") == 0)
2577 2467 ssl_library = CURLHELP_SSL_LIBRARY_NSS;
2578 if (verbose >= 2) 2468
2579 printf ("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library); 2469 if (verbose >= 2)
2580 2470 printf("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library);
2581 free (ssl_version); 2471
2582 2472 free(ssl_version);
2583 return ssl_library; 2473
2474 return ssl_library;
2584} 2475}
2585 2476
2586const char* 2477const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library ssl_library) {
2587curlhelp_get_ssl_library_string (curlhelp_ssl_library ssl_library) 2478 switch (ssl_library) {
2588{ 2479 case CURLHELP_SSL_LIBRARY_OPENSSL:
2589 switch (ssl_library) { 2480 return "OpenSSL";
2590 case CURLHELP_SSL_LIBRARY_OPENSSL: 2481 case CURLHELP_SSL_LIBRARY_LIBRESSL:
2591 return "OpenSSL"; 2482 return "LibreSSL";
2592 case CURLHELP_SSL_LIBRARY_LIBRESSL: 2483 case CURLHELP_SSL_LIBRARY_GNUTLS:
2593 return "LibreSSL"; 2484 return "GnuTLS";
2594 case CURLHELP_SSL_LIBRARY_GNUTLS: 2485 case CURLHELP_SSL_LIBRARY_NSS:
2595 return "GnuTLS"; 2486 return "NSS";
2596 case CURLHELP_SSL_LIBRARY_NSS: 2487 case CURLHELP_SSL_LIBRARY_UNKNOWN:
2597 return "NSS"; 2488 default:
2598 case CURLHELP_SSL_LIBRARY_UNKNOWN: 2489 return "unknown";
2599 default: 2490 }
2600 return "unknown";
2601 }
2602} 2491}
2603 2492
2604#ifdef LIBCURL_FEATURE_SSL 2493#ifdef LIBCURL_FEATURE_SSL
2605#ifndef USE_OPENSSL 2494# ifndef USE_OPENSSL
2606time_t 2495time_t parse_cert_date(const char *s) {
2607parse_cert_date (const char *s) 2496 struct tm tm;
2608{ 2497 time_t date;
2609 struct tm tm; 2498 char *res;
2610 time_t date; 2499
2611 char *res; 2500 if (!s)
2612 2501 return -1;
2613 if (!s) return -1; 2502
2614 2503 /* Jan 17 14:25:12 2020 GMT */
2615 /* Jan 17 14:25:12 2020 GMT */ 2504 res = strptime(s, "%Y-%m-%d %H:%M:%S GMT", &tm);
2616 res = strptime (s, "%Y-%m-%d %H:%M:%S GMT", &tm); 2505 /* Sep 11 12:00:00 2020 GMT */
2617 /* Sep 11 12:00:00 2020 GMT */ 2506 if (res == NULL)
2618 if (res == NULL) strptime (s, "%Y %m %d %H:%M:%S GMT", &tm); 2507 strptime(s, "%Y %m %d %H:%M:%S GMT", &tm);
2619 date = mktime (&tm); 2508 date = mktime(&tm);
2620 2509
2621 return date; 2510 return date;
2622} 2511}
2623 2512
2624/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to 2513/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to
2625 * OpenSSL could be this function 2514 * OpenSSL could be this function
2626 */ 2515 */
2627int 2516int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_warn, int days_till_exp_crit) {
2628net_noopenssl_check_certificate (cert_ptr_union* cert_ptr, int days_till_exp_warn, int days_till_exp_crit) 2517 int i;
2629{ 2518 struct curl_slist *slist;
2630 int i; 2519 int cname_found = 0;
2631 struct curl_slist* slist; 2520 char *start_date_str = NULL;
2632 int cname_found = 0; 2521 char *end_date_str = NULL;
2633 char* start_date_str = NULL; 2522 time_t start_date;
2634 char* end_date_str = NULL; 2523 time_t end_date;
2635 time_t start_date;
2636 time_t end_date;
2637 char *tz; 2524 char *tz;
2638 float time_left; 2525 float time_left;
2639 int days_left; 2526 int days_left;
@@ -2641,66 +2528,64 @@ net_noopenssl_check_certificate (cert_ptr_union* cert_ptr, int days_till_exp_war
2641 char timestamp[50] = ""; 2528 char timestamp[50] = "";
2642 int status = STATE_UNKNOWN; 2529 int status = STATE_UNKNOWN;
2643 2530
2644 if (verbose >= 2) 2531 if (verbose >= 2)
2645 printf ("**** REQUEST CERTIFICATES ****\n"); 2532 printf("**** REQUEST CERTIFICATES ****\n");
2646 2533
2647 for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) { 2534 for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) {
2648 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) { 2535 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) {
2649 /* find first common name in subject, 2536 /* find first common name in subject,
2650 * TODO: check alternative subjects for 2537 * TODO: check alternative subjects for
2651 * TODO: have a decent parser here and not a hack 2538 * TODO: have a decent parser here and not a hack
2652 * multi-host certificate, check wildcards 2539 * multi-host certificate, check wildcards
2653 */ 2540 */
2654 if (strncasecmp (slist->data, "Subject:", 8) == 0) { 2541 if (strncasecmp(slist->data, "Subject:", 8) == 0) {
2655 int d = 3; 2542 int d = 3;
2656 char* p = strstr (slist->data, "CN="); 2543 char *p = strstr(slist->data, "CN=");
2657 if (p == NULL) { 2544 if (p == NULL) {
2658 d = 5; 2545 d = 5;
2659 p = strstr (slist->data, "CN = "); 2546 p = strstr(slist->data, "CN = ");
2660 } 2547 }
2661 if (p != NULL) { 2548 if (p != NULL) {
2662 if (strncmp (host_name, p+d, strlen (host_name)) == 0) { 2549 if (strncmp(host_name, p + d, strlen(host_name)) == 0) {
2663 cname_found = 1; 2550 cname_found = 1;
2664 } 2551 }
2665 } 2552 }
2666 } else if (strncasecmp (slist->data, "Start Date:", 11) == 0) { 2553 } else if (strncasecmp(slist->data, "Start Date:", 11) == 0) {
2667 start_date_str = &slist->data[11]; 2554 start_date_str = &slist->data[11];
2668 } else if (strncasecmp (slist->data, "Expire Date:", 12) == 0) { 2555 } else if (strncasecmp(slist->data, "Expire Date:", 12) == 0) {
2669 end_date_str = &slist->data[12]; 2556 end_date_str = &slist->data[12];
2670 } else if (strncasecmp (slist->data, "Cert:", 5) == 0) { 2557 } else if (strncasecmp(slist->data, "Cert:", 5) == 0) {
2671 goto HAVE_FIRST_CERT; 2558 goto HAVE_FIRST_CERT;
2672 } 2559 }
2673 if (verbose >= 2) 2560 if (verbose >= 2)
2674 printf ("%d ** %s\n", i, slist->data); 2561 printf("%d ** %s\n", i, slist->data);
2675 } 2562 }
2676 } 2563 }
2677HAVE_FIRST_CERT: 2564HAVE_FIRST_CERT:
2678 2565
2679 if (verbose >= 2) 2566 if (verbose >= 2)
2680 printf ("**** REQUEST CERTIFICATES ****\n"); 2567 printf("**** REQUEST CERTIFICATES ****\n");
2681 2568
2682 if (!cname_found) { 2569 if (!cname_found) {
2683 printf("%s\n",_("CRITICAL - Cannot retrieve certificate subject.")); 2570 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
2684 return STATE_CRITICAL; 2571 return STATE_CRITICAL;
2685 } 2572 }
2686 2573
2687 start_date = parse_cert_date (start_date_str); 2574 start_date = parse_cert_date(start_date_str);
2688 if (start_date <= 0) { 2575 if (start_date <= 0) {
2689 snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), 2576 snprintf(msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), start_date_str);
2690 start_date_str); 2577 puts(msg);
2691 puts (msg); 2578 return STATE_WARNING;
2692 return STATE_WARNING; 2579 }
2693 } 2580
2694 2581 end_date = parse_cert_date(end_date_str);
2695 end_date = parse_cert_date (end_date_str); 2582 if (end_date <= 0) {
2696 if (end_date <= 0) { 2583 snprintf(msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), start_date_str);
2697 snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), 2584 puts(msg);
2698 start_date_str); 2585 return STATE_WARNING;
2699 puts (msg); 2586 }
2700 return STATE_WARNING; 2587
2701 } 2588 time_left = difftime(end_date, time(NULL));
2702
2703 time_left = difftime (end_date, time(NULL));
2704 days_left = time_left / 86400; 2589 days_left = time_left / 86400;
2705 tz = getenv("TZ"); 2590 tz = getenv("TZ");
2706 setenv("TZ", "GMT", 1); 2591 setenv("TZ", "GMT", 1);
@@ -2713,30 +2598,31 @@ HAVE_FIRST_CERT:
2713 tzset(); 2598 tzset();
2714 2599
2715 if (days_left > 0 && days_left <= days_till_exp_warn) { 2600 if (days_left > 0 && days_left <= days_till_exp_warn) {
2716 printf (_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", host_name, days_left, timestamp); 2601 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL",
2602 host_name, days_left, timestamp);
2717 if (days_left > days_till_exp_crit) 2603 if (days_left > days_till_exp_crit)
2718 status = STATE_WARNING; 2604 status = STATE_WARNING;
2719 else 2605 else
2720 status = STATE_CRITICAL; 2606 status = STATE_CRITICAL;
2721 } else if (days_left == 0 && time_left > 0) { 2607 } else if (days_left == 0 && time_left > 0) {
2722 if (time_left >= 3600) 2608 if (time_left >= 3600)
2723 time_remaining = (int) time_left / 3600; 2609 time_remaining = (int)time_left / 3600;
2724 else 2610 else
2725 time_remaining = (int) time_left / 60; 2611 time_remaining = (int)time_left / 60;
2726 2612
2727 printf (_("%s - Certificate '%s' expires in %u %s (%s)\n"), 2613 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name,
2728 (days_left>days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, time_remaining, 2614 time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp);
2729 time_left >= 3600 ? "hours" : "minutes", timestamp);
2730 2615
2731 if ( days_left > days_till_exp_crit) 2616 if (days_left > days_till_exp_crit)
2732 status = STATE_WARNING; 2617 status = STATE_WARNING;
2733 else 2618 else
2734 status = STATE_CRITICAL; 2619 status = STATE_CRITICAL;
2735 } else if (time_left < 0) { 2620 } else if (time_left < 0) {
2736 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp); 2621 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp);
2737 status=STATE_CRITICAL; 2622 status = STATE_CRITICAL;
2738 } else if (days_left == 0) { 2623 } else if (days_left == 0) {
2739 printf (_("%s - Certificate '%s' just expired (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", host_name, timestamp); 2624 printf(_("%s - Certificate '%s' just expired (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name,
2625 timestamp);
2740 if (days_left > days_till_exp_crit) 2626 if (days_left > days_till_exp_crit)
2741 status = STATE_WARNING; 2627 status = STATE_WARNING;
2742 else 2628 else
@@ -2747,5 +2633,5 @@ HAVE_FIRST_CERT:
2747 } 2633 }
2748 return status; 2634 return status;
2749} 2635}
2750#endif /* USE_OPENSSL */ 2636# endif /* USE_OPENSSL */
2751#endif /* LIBCURL_FEATURE_SSL */ 2637#endif /* LIBCURL_FEATURE_SSL */