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