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.c4587
1 files changed, 2247 insertions, 2340 deletions
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index e25d7a79..748201e8 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,1052 @@ 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 - %s"), 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 /* enable reading cookies from a file, and if the filename is an empty string, only enable the curl cookie engine */
822 822 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE");
823 /* do the request */ 823 /* now enable saving cookies to a file, but only if the filename is not an empty string, since writing it would fail */
824 res = curl_easy_perform(curl); 824 if (*cookie_jar_file)
825 825 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR");
826 if (verbose>=2 && http_post_data) 826 }
827 printf ("**** REQUEST CONTENT ****\n%s\n", http_post_data); 827
828 828 /* do the request */
829 /* free header and server IP resolve lists, we don't need it anymore */ 829 res = curl_easy_perform(curl);
830 curl_slist_free_all (header_list); header_list = NULL; 830
831 curl_slist_free_all (server_ips); server_ips = NULL; 831 if (verbose >= 2 && http_post_data)
832 if (host) { 832 printf("**** REQUEST CONTENT ****\n%s\n", http_post_data);
833 curl_slist_free_all (host); host = NULL; 833
834 } 834 /* free header and server IP resolve lists, we don't need it anymore */
835 835 curl_slist_free_all(header_list);
836 /* Curl errors, result in critical Nagios state */ 836 header_list = NULL;
837 if (res != CURLE_OK) { 837 curl_slist_free_all(server_ips);
838 snprintf (msg, 838 server_ips = NULL;
839 DEFAULT_BUFFER_SIZE, 839 if (host) {
840 _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), 840 curl_slist_free_all(host);
841 server_port, 841 host = NULL;
842 res, 842 }
843 errbuf[0] ? errbuf : curl_easy_strerror(res)); 843
844 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 844 /* Curl errors, result in critical Nagios state */
845 } 845 if (res != CURLE_OK) {
846 846 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), server_port,
847 /* certificate checks */ 847 res, errbuf[0] ? errbuf : curl_easy_strerror(res));
848 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
849 }
850
851 /* certificate checks */
848#ifdef LIBCURL_FEATURE_SSL 852#ifdef LIBCURL_FEATURE_SSL
849 if (use_ssl) { 853 if (use_ssl) {
850 if (check_cert) { 854 if (check_cert) {
851 if (is_openssl_callback) { 855 if (is_openssl_callback) {
852#ifdef USE_OPENSSL 856# ifdef USE_OPENSSL
853 /* check certificate with OpenSSL functions, curl has been built against OpenSSL 857 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
854 * and we actually have OpenSSL in the monitoring tools 858 * and we actually have OpenSSL in the monitoring tools
855 */ 859 */
856 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 860 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
857 if (!continue_after_check_cert) { 861 if (!continue_after_check_cert) {
858 return result_ssl; 862 return result_ssl;
859 } 863 }
860#else /* USE_OPENSSL */ 864# else /* USE_OPENSSL */
861 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n"); 865 die(STATE_CRITICAL,
862#endif /* USE_OPENSSL */ 866 "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n");
863 } else { 867# endif /* USE_OPENSSL */
864 int i; 868 } else {
865 struct curl_slist *slist; 869 int i;
866 870 struct curl_slist *slist;
867 cert_ptr.to_info = NULL; 871
868 res = curl_easy_getinfo (curl, CURLINFO_CERTINFO, &cert_ptr.to_info); 872 cert_ptr.to_info = NULL;
869 if (!res && cert_ptr.to_info) { 873 res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
870#ifdef USE_OPENSSL 874 if (!res && cert_ptr.to_info) {
871 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert parsing 875# ifdef USE_OPENSSL
872 * We only check the first certificate and assume it's the one of the server 876 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert parsing
873 */ 877 * We only check the first certificate and assume it's the one of the server
874 const char* raw_cert = NULL; 878 */
875 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) { 879 const char *raw_cert = NULL;
876 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) { 880 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) {
877 if (verbose >= 2) 881 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) {
878 printf ("%d ** %s\n", i, slist->data); 882 if (verbose >= 2)
879 if (strncmp (slist->data, "Cert:", 5) == 0) { 883 printf("%d ** %s\n", i, slist->data);
880 raw_cert = &slist->data[5]; 884 if (strncmp(slist->data, "Cert:", 5) == 0) {
881 goto GOT_FIRST_CERT; 885 raw_cert = &slist->data[5];
882 } 886 goto GOT_FIRST_CERT;
883 } 887 }
884 } 888 }
885GOT_FIRST_CERT: 889 }
886 if (!raw_cert) { 890 GOT_FIRST_CERT:
887 snprintf (msg, 891 if (!raw_cert) {
888 DEFAULT_BUFFER_SIZE, 892 snprintf(msg, DEFAULT_BUFFER_SIZE,
889 _("Cannot retrieve certificates from CERTINFO information - certificate data was empty")); 893 _("Cannot retrieve certificates from CERTINFO information - certificate data was empty"));
890 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 894 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
891 } 895 }
892 BIO* cert_BIO = BIO_new (BIO_s_mem()); 896 BIO *cert_BIO = BIO_new(BIO_s_mem());
893 BIO_write (cert_BIO, raw_cert, strlen(raw_cert)); 897 BIO_write(cert_BIO, raw_cert, strlen(raw_cert));
894 cert = PEM_read_bio_X509 (cert_BIO, NULL, NULL, NULL); 898 cert = PEM_read_bio_X509(cert_BIO, NULL, NULL, NULL);
895 if (!cert) { 899 if (!cert) {
896 snprintf (msg, 900 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Cannot read certificate from CERTINFO information - BIO error"));
897 DEFAULT_BUFFER_SIZE, 901 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
898 _("Cannot read certificate from CERTINFO information - BIO error")); 902 }
899 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 903 BIO_free(cert_BIO);
900 } 904 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
901 BIO_free (cert_BIO); 905 if (!continue_after_check_cert) {
902 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 906 return result_ssl;
903 if (!continue_after_check_cert) { 907 }
904 return result_ssl; 908# else /* USE_OPENSSL */
905 } 909 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal,
906#else /* USE_OPENSSL */ 910 * so we use the libcurl CURLINFO data
907 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal, 911 */
908 * so we use the libcurl CURLINFO data 912 result_ssl = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit);
909 */ 913 if (!continue_after_check_cert) {
910 result_ssl = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit); 914 return result_ssl;
911 if (!continue_after_check_cert) { 915 }
912 return result_ssl; 916# endif /* USE_OPENSSL */
913 } 917 } else {
914#endif /* USE_OPENSSL */ 918 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Cannot retrieve certificates - cURL returned %d - %s"), res,
915 } else { 919 curl_easy_strerror(res));
916 snprintf (msg, 920 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
917 DEFAULT_BUFFER_SIZE, 921 }
918 _("Cannot retrieve certificates - cURL returned %d - %s"), 922 }
919 res, 923 }
920 curl_easy_strerror(res)); 924 }
921 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
922 }
923 }
924 }
925 }
926#endif /* LIBCURL_FEATURE_SSL */ 925#endif /* LIBCURL_FEATURE_SSL */
927 926
928 /* we got the data and we executed the request in a given time, so we can append 927 /* we got the data and we executed the request in a given time, so we can append
929 * performance data to the answer always 928 * performance data to the answer always
930 */ 929 */
931 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_TOTAL_TIME, &total_time), "CURLINFO_TOTAL_TIME"); 930 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); 931 page_len = get_content_length(&header_buf, &body_buf);
933 if(show_extended_perfdata) { 932 if (show_extended_perfdata) {
934 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME"); 933 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"); 934 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"); 935 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"); 936 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", 937 "CURLINFO_STARTTRANSFER_TIME");
939 perfd_time(total_time), 938 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), 939 perfd_time_connect(time_connect), use_ssl ? perfd_time_ssl(time_appconnect - time_connect) : "",
941 perfd_time_connect(time_connect), 940 perfd_time_headers(time_headers - time_appconnect), perfd_time_firstbyte(time_firstbyte - time_headers),
942 use_ssl ? perfd_time_ssl (time_appconnect-time_connect) : "", 941 perfd_time_transfer(total_time - time_firstbyte));
943 perfd_time_headers(time_headers - time_appconnect), 942 } else {
944 perfd_time_firstbyte(time_firstbyte - time_headers), 943 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s", perfd_time(total_time), perfd_size(page_len));
945 perfd_time_transfer(total_time-time_firstbyte) 944 }
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 945
1073 char tmp[DEFAULT_BUFFER_SIZE]; 946 /* return a CRITICAL status if we couldn't read any data */
947 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0)
948 die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
1074 949
1075 snprintf (tmp, 950 /* get status line of answer, check sanity of HTTP code */
1076 DEFAULT_BUFFER_SIZE, 951 if (curlhelp_parse_statusline(header_buf.buf, &status_line) < 0) {
1077 _("%sheader '%s' not found on '%s://%s:%d%s', "), 952 snprintf(msg, DEFAULT_BUFFER_SIZE, "Unparsable status line in %.3g seconds response time|%s\n", total_time, perfstring);
1078 msg, 953 /* we cannot know the major/minor version here for sure as we cannot parse the first line */
1079 output_header_search, 954 die(STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg);
1080 use_ssl ? "https" : "http", 955 }
1081 host_name ? host_name : server_address, 956 status_line_initialized = true;
1082 server_port,
1083 server_url);
1084 957
1085 strcpy(msg, tmp); 958 /* get result code from cURL */
959 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE");
960 if (verbose >= 2)
961 printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", code);
1086 962
1087 result = STATE_CRITICAL; 963 /* print status line, header, body if verbose */
1088 } 964 if (verbose >= 2) {
1089 } 965 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf, (no_body ? " [[ skipped ]]" : body_buf.buf));
966 }
1090 967
1091 if (strlen (string_expect)) { 968 /* make sure the status line matches the response we are looking for */
1092 if (!strstr (body_buf.buf, string_expect)) { 969 if (!expected_statuscode(status_line.first_line, server_expect)) {
970 if (server_port == HTTP_PORT)
971 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), status_line.first_line);
972 else
973 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: %s\n"), server_port,
974 status_line.first_line);
975 die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, show_body ? "\n" : "", show_body ? body_buf.buf : "");
976 }
1093 977
1094 strncpy(&output_string_search[0],string_expect,sizeof(output_string_search)); 978 if (server_expect_yn) {
979 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), server_expect);
980 if (verbose)
981 printf("%s\n", msg);
982 result = STATE_OK;
983 } else {
984 /* illegal return codes result in a critical state */
985 if (code >= 600 || code < 100) {
986 die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg);
987 /* server errors result in a critical state */
988 } else if (code >= 500) {
989 result = STATE_CRITICAL;
990 /* client errors result in a warning state */
991 } else if (code >= 400) {
992 result = STATE_WARNING;
993 /* check redirected page if specified */
994 } else if (code >= 300) {
995 if (onredirect == STATE_DEPENDENT) {
996 if (followmethod == FOLLOW_LIBCURL) {
997 code = status_line.http_code;
998 } else {
999 /* old check_http style redirection, if we come
1000 * back here, we are in the same status as with
1001 * the libcurl method
1002 */
1003 redir(&header_buf);
1004 }
1005 } else {
1006 /* this is a specific code in the command line to
1007 * be returned when a redirection is encountered
1008 */
1009 }
1010 result = max_state_alt(onredirect, result);
1011 /* all other codes are considered ok */
1012 } else {
1013 result = STATE_OK;
1014 }
1015 }
1095 1016
1096 if(output_string_search[sizeof(output_string_search)-1]!='\0') { 1017 /* libcurl redirection internally, handle error states here */
1097 bcopy("...",&output_string_search[sizeof(output_string_search)-4],4); 1018 if (followmethod == FOLLOW_LIBCURL) {
1098 } 1019 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT");
1020 if (verbose >= 2)
1021 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth);
1022 if (redir_depth > max_depth) {
1023 snprintf(msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl", max_depth);
1024 die(STATE_WARNING, "HTTP WARNING - %s", msg);
1025 }
1026 }
1027
1028 /* check status codes, set exit status accordingly */
1029 if (status_line.http_code != code) {
1030 die(STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"),
1031 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg, code);
1032 }
1033
1034 if (maximum_age >= 0) {
1035 result = max_state_alt(check_document_dates(&header_buf, &msg), result);
1036 }
1037
1038 /* Page and Header content checks go here */
1039
1040 if (strlen(header_expect)) {
1041 if (!strstr(header_buf.buf, header_expect)) {
1042
1043 strncpy(&output_header_search[0], header_expect, sizeof(output_header_search));
1044
1045 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1046 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4);
1047 }
1048
1049 char tmp[DEFAULT_BUFFER_SIZE];
1050
1051 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg, output_header_search,
1052 use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url);
1053
1054 strcpy(msg, tmp);
1055
1056 result = STATE_CRITICAL;
1057 }
1058 }
1059
1060 if (strlen(string_expect)) {
1061 if (!strstr(body_buf.buf, string_expect)) {
1062
1063 strncpy(&output_string_search[0], string_expect, sizeof(output_string_search));
1064
1065 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1066 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4);
1067 }
1099 1068
1100 char tmp[DEFAULT_BUFFER_SIZE]; 1069 char tmp[DEFAULT_BUFFER_SIZE];
1101 1070
1102 snprintf (tmp, 1071 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search,
1103 DEFAULT_BUFFER_SIZE, 1072 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 1073
1112 strcpy(msg, tmp); 1074 strcpy(msg, tmp);
1113 1075
1114 result = STATE_CRITICAL; 1076 result = STATE_CRITICAL;
1115 } 1077 }
1116 } 1078 }
1117 1079
1118 if (strlen (regexp)) { 1080 if (strlen(regexp)) {
1119 errcode = regexec (&preg, body_buf.buf, REGS, pmatch, 0); 1081 errcode = regexec(&preg, body_buf.buf, REGS, pmatch, 0);
1120 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) { 1082 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) {
1121 /* OK - No-op to avoid changing the logic around it */ 1083 /* OK - No-op to avoid changing the logic around it */
1122 result = max_state_alt(STATE_OK, result); 1084 result = max_state_alt(STATE_OK, result);
1123 } 1085 } 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) { 1086 if (!invert_regex) {
1126 char tmp[DEFAULT_BUFFER_SIZE]; 1087 char tmp[DEFAULT_BUFFER_SIZE];
1127 1088
1128 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg); 1089 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg);
1129 strcpy(msg, tmp); 1090 strcpy(msg, tmp);
1130 1091
1131 } else { 1092 } else {
1132 char tmp[DEFAULT_BUFFER_SIZE]; 1093 char tmp[DEFAULT_BUFFER_SIZE];
1133 1094
1134 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg); 1095 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg);
1135 strcpy(msg, tmp); 1096 strcpy(msg, tmp);
1136
1137 } 1097 }
1138 result = state_regex; 1098 result = state_regex;
1139 } else { 1099 } else {
1140 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1100 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1141 1101
1142 char tmp[DEFAULT_BUFFER_SIZE]; 1102 char tmp[DEFAULT_BUFFER_SIZE];
1143 1103
1144 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf); 1104 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf);
1145 strcpy(msg, tmp); 1105 strcpy(msg, tmp);
1146 result = STATE_UNKNOWN; 1106 result = STATE_UNKNOWN;
1147 } 1107 }
1148 } 1108 }
1149 1109
1150 /* make sure the page is of an appropriate size */ 1110 /* make sure the page is of an appropriate size */
1151 if ((max_page_len > 0) && (page_len > max_page_len)) { 1111 if ((max_page_len > 0) && (page_len > max_page_len)) {
1152 char tmp[DEFAULT_BUFFER_SIZE]; 1112 char tmp[DEFAULT_BUFFER_SIZE];
1153 1113
1154 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len); 1114 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len);
1155 1115
1156 strcpy(msg, tmp); 1116 strcpy(msg, tmp);
1157 1117
@@ -1160,1281 +1120,1233 @@ GOT_FIRST_CERT:
1160 } else if ((min_page_len > 0) && (page_len < min_page_len)) { 1120 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1161 char tmp[DEFAULT_BUFFER_SIZE]; 1121 char tmp[DEFAULT_BUFFER_SIZE];
1162 1122
1163 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len); 1123 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len);
1164 strcpy(msg, tmp); 1124 strcpy(msg, tmp);
1165 result = max_state_alt(STATE_WARNING, result); 1125 result = max_state_alt(STATE_WARNING, result);
1166 } 1126 }
1167 1127
1168 /* -w, -c: check warning and critical level */ 1128 /* -w, -c: check warning and critical level */
1169 result = max_state_alt(get_status(total_time, thlds), result); 1129 result = max_state_alt(get_status(total_time, thlds), result);
1170 1130
1171 /* Cut-off trailing characters */ 1131 /* Cut-off trailing characters */
1172 if (strlen(msg) >= 2) { 1132 if (strlen(msg) >= 2) {
1173 if(msg[strlen(msg)-2] == ',') 1133 if (msg[strlen(msg) - 2] == ',')
1174 msg[strlen(msg)-2] = '\0'; 1134 msg[strlen(msg) - 2] = '\0';
1175 else 1135 else
1176 msg[strlen(msg)-3] = '\0'; 1136 msg[strlen(msg) - 3] = '\0';
1177 } 1137 }
1178 1138
1179 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */ 1139 /* 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", 1140 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), 1141 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, 1142 strlen(msg) > 0 ? " - " : "", msg, page_len, total_time, (display_html ? "</A>" : ""), perfstring, (show_body ? body_buf.buf : ""),
1183 strlen(msg) > 0 ? " - " : "", 1143 (show_body ? "\n" : ""));
1184 msg, page_len, total_time, 1144
1185 (display_html ? "</A>" : ""), 1145 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} 1146}
1192 1147
1193int 1148int uri_strcmp(const UriTextRangeA range, const char *s) {
1194uri_strcmp (const UriTextRangeA range, const char* s) 1149 if (!range.first)
1195{ 1150 return -1;
1196 if (!range.first) return -1; 1151 if ((size_t)(range.afterLast - range.first) < strlen(s))
1197 if ( (size_t)(range.afterLast - range.first) < strlen (s) ) return -1; 1152 return -1;
1198 return strncmp (s, range.first, min( (size_t)(range.afterLast - range.first), strlen (s))); 1153 return strncmp(s, range.first, min((size_t)(range.afterLast - range.first), strlen(s)));
1199} 1154}
1200 1155
1201char* 1156char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) {
1202uri_string (const UriTextRangeA range, char* buf, size_t buflen) 1157 if (!range.first)
1203{ 1158 return "(null)";
1204 if (!range.first) return "(null)"; 1159 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))); 1160 buf[max(buflen - 1, (size_t)(range.afterLast - range.first))] = '\0';
1206 buf[max (buflen-1, (size_t)(range.afterLast - range.first))] = '\0'; 1161 buf[range.afterLast - range.first] = '\0';
1207 buf[range.afterLast - range.first] = '\0'; 1162 return buf;
1208 return buf;
1209} 1163}
1210 1164
1211void 1165void redir(curlhelp_write_curlbuf *header_buf) {
1212redir (curlhelp_write_curlbuf* header_buf) 1166 char *location = NULL;
1213{ 1167 curlhelp_statusline status_line;
1214 char *location = NULL; 1168 struct phr_header headers[255];
1215 curlhelp_statusline status_line; 1169 size_t nof_headers = 255;
1216 struct phr_header headers[255]; 1170 size_t msglen;
1217 size_t nof_headers = 255; 1171 char buf[DEFAULT_BUFFER_SIZE];
1218 size_t msglen; 1172 char ipstr[INET_ADDR_MAX_SIZE];
1219 char buf[DEFAULT_BUFFER_SIZE]; 1173 int new_port;
1220 char ipstr[INET_ADDR_MAX_SIZE]; 1174 char *new_host;
1221 int new_port; 1175 char *new_url;
1222 char *new_host; 1176
1223 char *new_url; 1177 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
1224 1178 &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 1179
1229 if (res == -1) { 1180 if (res == -1) {
1230 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 1181 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
1231 } 1182 }
1232 1183
1233 location = get_header_value (headers, nof_headers, "location"); 1184 location = get_header_value(headers, nof_headers, "location");
1234 1185
1235 if (verbose >= 2) 1186 if (verbose >= 2)
1236 printf(_("* Seen redirect location %s\n"), location); 1187 printf(_("* Seen redirect location %s\n"), location);
1237 1188
1238 if (++redir_depth > max_depth) 1189 if (++redir_depth > max_depth)
1239 die (STATE_WARNING, 1190 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"), 1191 (display_html ? "</A>" : ""));
1241 max_depth, location, (display_html ? "</A>" : "")); 1192
1242 1193 UriParserStateA state;
1243 UriParserStateA state; 1194 UriUriA uri;
1244 UriUriA uri; 1195 state.uri = &uri;
1245 state.uri = &uri; 1196 if (uriParseUriA(&state, location) != URI_SUCCESS) {
1246 if (uriParseUriA (&state, location) != URI_SUCCESS) { 1197 if (state.errorCode == URI_ERROR_SYNTAX) {
1247 if (state.errorCode == URI_ERROR_SYNTAX) { 1198 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"), location, (display_html ? "</A>" : ""));
1248 die (STATE_UNKNOWN, 1199 } else if (state.errorCode == URI_ERROR_MALLOC) {
1249 _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"), 1200 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1250 location, (display_html ? "</A>" : "")); 1201 }
1251 } else if (state.errorCode == URI_ERROR_MALLOC) { 1202 }
1252 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 1203
1253 } 1204 if (verbose >= 2) {
1254 } 1205 printf(_("** scheme: %s\n"), uri_string(uri.scheme, buf, DEFAULT_BUFFER_SIZE));
1255 1206 printf(_("** host: %s\n"), uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1256 if (verbose >= 2) { 1207 printf(_("** port: %s\n"), uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
1257 printf (_("** scheme: %s\n"), 1208 if (uri.hostData.ip4) {
1258 uri_string (uri.scheme, buf, DEFAULT_BUFFER_SIZE)); 1209 inet_ntop(AF_INET, uri.hostData.ip4->data, ipstr, sizeof(ipstr));
1259 printf (_("** host: %s\n"), 1210 printf(_("** IPv4: %s\n"), ipstr);
1260 uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE)); 1211 }
1261 printf (_("** port: %s\n"), 1212 if (uri.hostData.ip6) {
1262 uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE)); 1213 inet_ntop(AF_INET, uri.hostData.ip6->data, ipstr, sizeof(ipstr));
1263 if (uri.hostData.ip4) { 1214 printf(_("** IPv6: %s\n"), ipstr);
1264 inet_ntop (AF_INET, uri.hostData.ip4->data, ipstr, sizeof (ipstr)); 1215 }
1265 printf (_("** IPv4: %s\n"), ipstr); 1216 if (uri.pathHead) {
1266 } 1217 printf(_("** path: "));
1267 if (uri.hostData.ip6) { 1218 const UriPathSegmentA *p = uri.pathHead;
1268 inet_ntop (AF_INET, uri.hostData.ip6->data, ipstr, sizeof (ipstr)); 1219 for (; p; p = p->next) {
1269 printf (_("** IPv6: %s\n"), ipstr); 1220 printf("/%s", uri_string(p->text, buf, DEFAULT_BUFFER_SIZE));
1270 } 1221 }
1271 if (uri.pathHead) { 1222 puts("");
1272 printf (_("** path: ")); 1223 }
1273 const UriPathSegmentA* p = uri.pathHead; 1224 if (uri.query.first) {
1274 for (; p; p = p->next) { 1225 printf(_("** query: %s\n"), uri_string(uri.query, buf, DEFAULT_BUFFER_SIZE));
1275 printf ("/%s", uri_string (p->text, buf, DEFAULT_BUFFER_SIZE)); 1226 }
1276 } 1227 if (uri.fragment.first) {
1277 puts (""); 1228 printf(_("** fragment: %s\n"), uri_string(uri.fragment, buf, DEFAULT_BUFFER_SIZE));
1278 } 1229 }
1279 if (uri.query.first) { 1230 }
1280 printf (_("** query: %s\n"), 1231
1281 uri_string (uri.query, buf, DEFAULT_BUFFER_SIZE)); 1232 if (uri.scheme.first) {
1282 } 1233 if (!uri_strcmp(uri.scheme, "https"))
1283 if (uri.fragment.first) { 1234 use_ssl = true;
1284 printf (_("** fragment: %s\n"), 1235 else
1285 uri_string (uri.fragment, buf, DEFAULT_BUFFER_SIZE)); 1236 use_ssl = false;
1286 } 1237 }
1287 } 1238
1288 1239 /* we do a sloppy test here only, because uriparser would have failed
1289 if (uri.scheme.first) { 1240 * above, if the port would be invalid, we just check for MAX_PORT
1290 if (!uri_strcmp (uri.scheme, "https")) 1241 */
1291 use_ssl = true; 1242 if (uri.portText.first) {
1292 else 1243 new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
1293 use_ssl = false; 1244 } else {
1294 } 1245 new_port = HTTP_PORT;
1295 1246 if (use_ssl)
1296 /* we do a sloppy test here only, because uriparser would have failed 1247 new_port = HTTPS_PORT;
1297 * above, if the port would be invalid, we just check for MAX_PORT 1248 }
1298 */ 1249 if (new_port > MAX_PORT)
1299 if (uri.portText.first) { 1250 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)); 1251
1301 } else { 1252 /* by RFC 7231 relative URLs in Location should be taken relative to
1302 new_port = HTTP_PORT; 1253 * the original URL, so we try to form a new absolute URL here
1303 if (use_ssl) 1254 */
1304 new_port = HTTPS_PORT; 1255 if (!uri.scheme.first && !uri.hostText.first) {
1305 } 1256 new_host = strdup(host_name ? host_name : server_address);
1306 if (new_port > MAX_PORT) 1257 new_port = server_port;
1307 die (STATE_UNKNOWN, 1258 if (use_ssl)
1308 _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"), 1259 uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE);
1309 MAX_PORT, location, display_html ? "</A>" : ""); 1260 } else {
1310 1261 new_host = strdup(uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1311 /* by RFC 7231 relative URLs in Location should be taken relative to 1262 }
1312 * the original URL, so we try to form a new absolute URL here 1263
1313 */ 1264 /* compose new path */
1314 if (!uri.scheme.first && !uri.hostText.first) { 1265 /* TODO: handle fragments and query part of URL */
1315 new_host = strdup (host_name ? host_name : server_address); 1266 new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE);
1316 new_port = server_port; 1267 if (uri.pathHead) {
1317 if(use_ssl) 1268 const UriPathSegmentA *p = uri.pathHead;
1318 uri_string (uri.scheme, "https", DEFAULT_BUFFER_SIZE); 1269 for (; p; p = p->next) {
1319 } else { 1270 strncat(new_url, "/", DEFAULT_BUFFER_SIZE);
1320 new_host = strdup (uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE)); 1271 strncat(new_url, uri_string(p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE - 1);
1321 } 1272 }
1322 1273 }
1323 /* compose new path */ 1274
1324 /* TODO: handle fragments and query part of URL */ 1275 if (server_port == new_port && !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) &&
1325 new_url = (char *)calloc( 1, DEFAULT_BUFFER_SIZE); 1276 (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && !strcmp(server_url, new_url))
1326 if (uri.pathHead) { 1277 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; 1278 new_host, new_port, new_url, (display_html ? "</A>" : ""));
1328 for (; p; p = p->next) { 1279
1329 strncat (new_url, "/", DEFAULT_BUFFER_SIZE); 1280 /* set new values for redirected request */
1330 strncat (new_url, uri_string (p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE-1); 1281
1331 } 1282 if (!(followsticky & STICKY_HOST)) {
1332 } 1283 free(server_address);
1333 1284 server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1334 if (server_port==new_port && 1285 }
1335 !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) && 1286 if (!(followsticky & STICKY_PORT)) {
1336 (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && 1287 server_port = (unsigned short)new_port;
1337 !strcmp(server_url, new_url)) 1288 }
1338 die (STATE_CRITICAL, 1289
1339 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), 1290 free(host_name);
1340 use_ssl ? "https" : "http", new_host, new_port, new_url, (display_html ? "</A>" : "")); 1291 host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1341 1292
1342 /* set new values for redirected request */ 1293 /* reset virtual port */
1343 1294 virtual_port = server_port;
1344 if (!(followsticky & STICKY_HOST)) { 1295
1345 free (server_address); 1296 free(new_host);
1346 server_address = strndup (new_host, MAX_IPV4_HOSTLENGTH); 1297 free(server_url);
1347 } 1298 server_url = new_url;
1348 if (!(followsticky & STICKY_PORT)) { 1299
1349 server_port = (unsigned short)new_port; 1300 uriFreeUriMembersA(&uri);
1350 } 1301
1351 1302 if (verbose)
1352 free (host_name); 1303 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); 1304 server_url);
1354 1305
1355 /* reset virtual port */ 1306 /* TODO: the hash component MUST be taken from the original URL and
1356 virtual_port = server_port; 1307 * attached to the URL in Location
1357 1308 */
1358 free(new_host); 1309
1359 free (server_url); 1310 cleanup();
1360 server_url = new_url; 1311 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} 1312}
1375 1313
1376/* check whether a file exists */ 1314/* check whether a file exists */
1377void 1315void test_file(char *path) {
1378test_file (char *path) 1316 if (access(path, R_OK) == 0)
1379{ 1317 return;
1380 if (access(path, R_OK) == 0) 1318 usage2(_("file does not exist or is not readable"), path);
1381 return;
1382 usage2 (_("file does not exist or is not readable"), path);
1383} 1319}
1384 1320
1385bool 1321bool process_arguments(int argc, char **argv) {
1386process_arguments (int argc, char **argv) 1322 char *p;
1387{ 1323 int c = 1;
1388 char *p; 1324 char *temp;
1389 int c = 1; 1325
1390 char *temp; 1326 enum {
1391 1327 INVERT_REGEX = CHAR_MAX + 1,
1392 enum { 1328 SNI_OPTION,
1393 INVERT_REGEX = CHAR_MAX + 1, 1329 MAX_REDIRS_OPTION,
1394 SNI_OPTION, 1330 CONTINUE_AFTER_CHECK_CERT,
1395 MAX_REDIRS_OPTION, 1331 CA_CERT_OPTION,
1396 CONTINUE_AFTER_CHECK_CERT, 1332 HTTP_VERSION_OPTION,
1397 CA_CERT_OPTION, 1333 AUTOMATIC_DECOMPRESSION,
1398 HTTP_VERSION_OPTION, 1334 COOKIE_JAR,
1399 AUTOMATIC_DECOMPRESSION, 1335 HAPROXY_PROTOCOL,
1400 COOKIE_JAR, 1336 STATE_REGEX
1401 HAPROXY_PROTOCOL, 1337 };
1402 STATE_REGEX 1338
1403 }; 1339 int option = 0;
1404 1340 int got_plus = 0;
1405 int option = 0; 1341 static struct option longopts[] = {STD_LONG_OPTS,
1406 int got_plus = 0; 1342 {"link", no_argument, 0, 'L'},
1407 static struct option longopts[] = { 1343 {"nohtml", no_argument, 0, 'n'},
1408 STD_LONG_OPTS, 1344 {"ssl", optional_argument, 0, 'S'},
1409 {"link", no_argument, 0, 'L'}, 1345 {"sni", no_argument, 0, SNI_OPTION},
1410 {"nohtml", no_argument, 0, 'n'}, 1346 {"post", required_argument, 0, 'P'},
1411 {"ssl", optional_argument, 0, 'S'}, 1347 {"method", required_argument, 0, 'j'},
1412 {"sni", no_argument, 0, SNI_OPTION}, 1348 {"IP-address", required_argument, 0, 'I'},
1413 {"post", required_argument, 0, 'P'}, 1349 {"url", required_argument, 0, 'u'},
1414 {"method", required_argument, 0, 'j'}, 1350 {"port", required_argument, 0, 'p'},
1415 {"IP-address", required_argument, 0, 'I'}, 1351 {"authorization", required_argument, 0, 'a'},
1416 {"url", required_argument, 0, 'u'}, 1352 {"proxy-authorization", required_argument, 0, 'b'},
1417 {"port", required_argument, 0, 'p'}, 1353 {"header-string", required_argument, 0, 'd'},
1418 {"authorization", required_argument, 0, 'a'}, 1354 {"string", required_argument, 0, 's'},
1419 {"proxy-authorization", required_argument, 0, 'b'}, 1355 {"expect", required_argument, 0, 'e'},
1420 {"header-string", required_argument, 0, 'd'}, 1356 {"regex", required_argument, 0, 'r'},
1421 {"string", required_argument, 0, 's'}, 1357 {"ereg", required_argument, 0, 'r'},
1422 {"expect", required_argument, 0, 'e'}, 1358 {"eregi", required_argument, 0, 'R'},
1423 {"regex", required_argument, 0, 'r'}, 1359 {"linespan", no_argument, 0, 'l'},
1424 {"ereg", required_argument, 0, 'r'}, 1360 {"onredirect", required_argument, 0, 'f'},
1425 {"eregi", required_argument, 0, 'R'}, 1361 {"certificate", required_argument, 0, 'C'},
1426 {"linespan", no_argument, 0, 'l'}, 1362 {"client-cert", required_argument, 0, 'J'},
1427 {"onredirect", required_argument, 0, 'f'}, 1363 {"private-key", required_argument, 0, 'K'},
1428 {"certificate", required_argument, 0, 'C'}, 1364 {"ca-cert", required_argument, 0, CA_CERT_OPTION},
1429 {"client-cert", required_argument, 0, 'J'}, 1365 {"verify-cert", no_argument, 0, 'D'},
1430 {"private-key", required_argument, 0, 'K'}, 1366 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
1431 {"ca-cert", required_argument, 0, CA_CERT_OPTION}, 1367 {"useragent", required_argument, 0, 'A'},
1432 {"verify-cert", no_argument, 0, 'D'}, 1368 {"header", required_argument, 0, 'k'},
1433 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT}, 1369 {"no-body", no_argument, 0, 'N'},
1434 {"useragent", required_argument, 0, 'A'}, 1370 {"max-age", required_argument, 0, 'M'},
1435 {"header", required_argument, 0, 'k'}, 1371 {"content-type", required_argument, 0, 'T'},
1436 {"no-body", no_argument, 0, 'N'}, 1372 {"pagesize", required_argument, 0, 'm'},
1437 {"max-age", required_argument, 0, 'M'}, 1373 {"invert-regex", no_argument, NULL, INVERT_REGEX},
1438 {"content-type", required_argument, 0, 'T'}, 1374 {"state-regex", required_argument, 0, STATE_REGEX},
1439 {"pagesize", required_argument, 0, 'm'}, 1375 {"use-ipv4", no_argument, 0, '4'},
1440 {"invert-regex", no_argument, NULL, INVERT_REGEX}, 1376 {"use-ipv6", no_argument, 0, '6'},
1441 {"state-regex", required_argument, 0, STATE_REGEX}, 1377 {"extended-perfdata", no_argument, 0, 'E'},
1442 {"use-ipv4", no_argument, 0, '4'}, 1378 {"show-body", no_argument, 0, 'B'},
1443 {"use-ipv6", no_argument, 0, '6'}, 1379 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
1444 {"extended-perfdata", no_argument, 0, 'E'}, 1380 {"http-version", required_argument, 0, HTTP_VERSION_OPTION},
1445 {"show-body", no_argument, 0, 'B'}, 1381 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION},
1446 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION}, 1382 {"cookie-jar", required_argument, 0, COOKIE_JAR},
1447 {"http-version", required_argument, 0, HTTP_VERSION_OPTION}, 1383 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL},
1448 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION}, 1384 {0, 0, 0, 0}};
1449 {"cookie-jar", required_argument, 0, COOKIE_JAR}, 1385
1450 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL}, 1386 if (argc < 2)
1451 {0, 0, 0, 0} 1387 return false;
1452 }; 1388
1453 1389 /* support check_http compatible arguments */
1454 if (argc < 2) 1390 for (c = 1; c < argc; c++) {
1455 return false; 1391 if (strcmp("-to", argv[c]) == 0)
1456 1392 strcpy(argv[c], "-t");
1457 /* support check_http compatible arguments */ 1393 if (strcmp("-hn", argv[c]) == 0)
1458 for (c = 1; c < argc; c++) { 1394 strcpy(argv[c], "-H");
1459 if (strcmp ("-to", argv[c]) == 0) 1395 if (strcmp("-wt", argv[c]) == 0)
1460 strcpy (argv[c], "-t"); 1396 strcpy(argv[c], "-w");
1461 if (strcmp ("-hn", argv[c]) == 0) 1397 if (strcmp("-ct", argv[c]) == 0)
1462 strcpy (argv[c], "-H"); 1398 strcpy(argv[c], "-c");
1463 if (strcmp ("-wt", argv[c]) == 0) 1399 if (strcmp("-nohtml", argv[c]) == 0)
1464 strcpy (argv[c], "-w"); 1400 strcpy(argv[c], "-n");
1465 if (strcmp ("-ct", argv[c]) == 0) 1401 }
1466 strcpy (argv[c], "-c"); 1402
1467 if (strcmp ("-nohtml", argv[c]) == 0) 1403 server_url = strdup(DEFAULT_SERVER_URL);
1468 strcpy (argv[c], "-n"); 1404
1469 } 1405 while (1) {
1470 1406 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); 1407 if (c == -1 || c == EOF || c == 1)
1472 1408 break;
1473 while (1) { 1409
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); 1410 switch (c) {
1475 if (c == -1 || c == EOF || c == 1) 1411 case 'h':
1476 break; 1412 print_help();
1477 1413 exit(STATE_UNKNOWN);
1478 switch (c) { 1414 break;
1479 case 'h': 1415 case 'V':
1480 print_help(); 1416 print_revision(progname, NP_VERSION);
1481 exit(STATE_UNKNOWN); 1417 print_curl_version();
1482 break; 1418 exit(STATE_UNKNOWN);
1483 case 'V': 1419 break;
1484 print_revision(progname, NP_VERSION); 1420 case 'v':
1485 print_curl_version(); 1421 verbose++;
1486 exit(STATE_UNKNOWN); 1422 break;
1487 break; 1423 case 't': /* timeout period */
1488 case 'v': 1424 if (!is_intnonneg(optarg))
1489 verbose++; 1425 usage2(_("Timeout interval must be a positive integer"), optarg);
1490 break; 1426 else
1491 case 't': /* timeout period */ 1427 socket_timeout = (int)strtol(optarg, NULL, 10);
1492 if (!is_intnonneg (optarg)) 1428 break;
1493 usage2 (_("Timeout interval must be a positive integer"), optarg); 1429 case 'c': /* critical time threshold */
1494 else 1430 critical_thresholds = optarg;
1495 socket_timeout = (int)strtol (optarg, NULL, 10); 1431 break;
1496 break; 1432 case 'w': /* warning time threshold */
1497 case 'c': /* critical time threshold */ 1433 warning_thresholds = optarg;
1498 critical_thresholds = optarg; 1434 break;
1499 break; 1435 case 'H': /* virtual host */
1500 case 'w': /* warning time threshold */ 1436 host_name = strdup(optarg);
1501 warning_thresholds = optarg; 1437 if (host_name[0] == '[') {
1502 break; 1438 if ((p = strstr(host_name, "]:")) != NULL) { /* [IPv6]:port */
1503 case 'H': /* virtual host */ 1439 virtual_port = atoi(p + 2);
1504 host_name = strdup (optarg); 1440 /* cut off the port */
1505 if (host_name[0] == '[') { 1441 host_name_length = strlen(host_name) - strlen(p) - 1;
1506 if ((p = strstr (host_name, "]:")) != NULL) { /* [IPv6]:port */ 1442 free(host_name);
1507 virtual_port = atoi (p + 2); 1443 host_name = strndup(optarg, host_name_length);
1508 /* cut off the port */ 1444 }
1509 host_name_length = strlen (host_name) - strlen (p) - 1; 1445 } else if ((p = strchr(host_name, ':')) != NULL && strchr(++p, ':') == NULL) { /* IPv4:port or host:port */
1510 free (host_name); 1446 virtual_port = atoi(p);
1511 host_name = strndup (optarg, host_name_length); 1447 /* cut off the port */
1512 } 1448 host_name_length = strlen(host_name) - strlen(p) - 1;
1513 } else if ((p = strchr (host_name, ':')) != NULL 1449 free(host_name);
1514 && strchr (++p, ':') == NULL) { /* IPv4:port or host:port */ 1450 host_name = strndup(optarg, host_name_length);
1515 virtual_port = atoi (p); 1451 }
1516 /* cut off the port */ 1452 break;
1517 host_name_length = strlen (host_name) - strlen (p) - 1; 1453 case 'I': /* internet address */
1518 free (host_name); 1454 server_address = strdup(optarg);
1519 host_name = strndup (optarg, host_name_length); 1455 break;
1520 } 1456 case 'u': /* URL path */
1521 break; 1457 server_url = strdup(optarg);
1522 case 'I': /* internet address */ 1458 break;
1523 server_address = strdup (optarg); 1459 case 'p': /* Server port */
1524 break; 1460 if (!is_intnonneg(optarg))
1525 case 'u': /* URL path */ 1461 usage2(_("Invalid port number, expecting a non-negative number"), optarg);
1526 server_url = strdup (optarg); 1462 else {
1527 break; 1463 if (strtol(optarg, NULL, 10) > MAX_PORT)
1528 case 'p': /* Server port */ 1464 usage2(_("Invalid port number, supplied port number is too big"), optarg);
1529 if (!is_intnonneg (optarg)) 1465 server_port = (unsigned short)strtol(optarg, NULL, 10);
1530 usage2 (_("Invalid port number, expecting a non-negative number"), optarg); 1466 specify_port = true;
1531 else { 1467 }
1532 if( strtol(optarg, NULL, 10) > MAX_PORT) 1468 break;
1533 usage2 (_("Invalid port number, supplied port number is too big"), optarg); 1469 case 'a': /* authorization info */
1534 server_port = (unsigned short)strtol(optarg, NULL, 10); 1470 strncpy(user_auth, optarg, MAX_INPUT_BUFFER - 1);
1535 specify_port = true; 1471 user_auth[MAX_INPUT_BUFFER - 1] = 0;
1536 } 1472 break;
1537 break; 1473 case 'b': /* proxy-authorization info */
1538 case 'a': /* authorization info */ 1474 strncpy(proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
1539 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1); 1475 proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
1540 user_auth[MAX_INPUT_BUFFER - 1] = 0; 1476 break;
1541 break; 1477 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
1542 case 'b': /* proxy-authorization info */ 1478 if (!http_post_data)
1543 strncpy (proxy_auth, optarg, MAX_INPUT_BUFFER - 1); 1479 http_post_data = strdup(optarg);
1544 proxy_auth[MAX_INPUT_BUFFER - 1] = 0; 1480 if (!http_method)
1545 break; 1481 http_method = strdup("POST");
1546 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */ 1482 break;
1547 if (! http_post_data) 1483 case 'j': /* Set HTTP method */
1548 http_post_data = strdup (optarg); 1484 if (http_method)
1549 if (! http_method) 1485 free(http_method);
1550 http_method = strdup("POST"); 1486 http_method = strdup(optarg);
1551 break; 1487 break;
1552 case 'j': /* Set HTTP method */ 1488 case 'A': /* useragent */
1553 if (http_method) 1489 strncpy(user_agent, optarg, DEFAULT_BUFFER_SIZE);
1554 free(http_method); 1490 user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0';
1555 http_method = strdup (optarg); 1491 break;
1556 break; 1492 case 'k': /* Additional headers */
1557 case 'A': /* useragent */ 1493 if (http_opt_headers_count == 0)
1558 strncpy (user_agent, optarg, DEFAULT_BUFFER_SIZE); 1494 http_opt_headers = malloc(sizeof(char *) * (++http_opt_headers_count));
1559 user_agent[DEFAULT_BUFFER_SIZE-1] = '\0'; 1495 else
1560 break; 1496 http_opt_headers = realloc(http_opt_headers, sizeof(char *) * (++http_opt_headers_count));
1561 case 'k': /* Additional headers */ 1497 http_opt_headers[http_opt_headers_count - 1] = optarg;
1562 if (http_opt_headers_count == 0) 1498 break;
1563 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count)); 1499 case 'L': /* show html link */
1564 else 1500 display_html = true;
1565 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count)); 1501 break;
1566 http_opt_headers[http_opt_headers_count - 1] = optarg; 1502 case 'n': /* do not show html link */
1567 break; 1503 display_html = false;
1568 case 'L': /* show html link */ 1504 break;
1569 display_html = true; 1505 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 1506#ifdef LIBCURL_FEATURE_SSL
1576 if ((temp=strchr(optarg,','))!=NULL) { 1507 if ((temp = strchr(optarg, ',')) != NULL) {
1577 *temp='\0'; 1508 *temp = '\0';
1578 if (!is_intnonneg (optarg)) 1509 if (!is_intnonneg(optarg))
1579 usage2 (_("Invalid certificate expiration period"), optarg); 1510 usage2(_("Invalid certificate expiration period"), optarg);
1580 days_till_exp_warn = atoi(optarg); 1511 days_till_exp_warn = atoi(optarg);
1581 *temp=','; 1512 *temp = ',';
1582 temp++; 1513 temp++;
1583 if (!is_intnonneg (temp)) 1514 if (!is_intnonneg(temp))
1584 usage2 (_("Invalid certificate expiration period"), temp); 1515 usage2(_("Invalid certificate expiration period"), temp);
1585 days_till_exp_crit = atoi (temp); 1516 days_till_exp_crit = atoi(temp);
1586 } 1517 } else {
1587 else { 1518 days_till_exp_crit = 0;
1588 days_till_exp_crit=0; 1519 if (!is_intnonneg(optarg))
1589 if (!is_intnonneg (optarg)) 1520 usage2(_("Invalid certificate expiration period"), optarg);
1590 usage2 (_("Invalid certificate expiration period"), optarg); 1521 days_till_exp_warn = atoi(optarg);
1591 days_till_exp_warn = atoi (optarg); 1522 }
1592 } 1523 check_cert = true;
1593 check_cert = true; 1524 goto enable_ssl;
1594 goto enable_ssl;
1595#endif 1525#endif
1596 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */ 1526 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
1597#ifdef HAVE_SSL 1527#ifdef HAVE_SSL
1598 continue_after_check_cert = true; 1528 continue_after_check_cert = true;
1599 break; 1529 break;
1600#endif 1530#endif
1601 case 'J': /* use client certificate */ 1531 case 'J': /* use client certificate */
1602#ifdef LIBCURL_FEATURE_SSL 1532#ifdef LIBCURL_FEATURE_SSL
1603 test_file(optarg); 1533 test_file(optarg);
1604 client_cert = optarg; 1534 client_cert = optarg;
1605 goto enable_ssl; 1535 goto enable_ssl;
1606#endif 1536#endif
1607 case 'K': /* use client private key */ 1537 case 'K': /* use client private key */
1608#ifdef LIBCURL_FEATURE_SSL 1538#ifdef LIBCURL_FEATURE_SSL
1609 test_file(optarg); 1539 test_file(optarg);
1610 client_privkey = optarg; 1540 client_privkey = optarg;
1611 goto enable_ssl; 1541 goto enable_ssl;
1612#endif 1542#endif
1613#ifdef LIBCURL_FEATURE_SSL 1543#ifdef LIBCURL_FEATURE_SSL
1614 case CA_CERT_OPTION: /* use CA chain file */ 1544 case CA_CERT_OPTION: /* use CA chain file */
1615 test_file(optarg); 1545 test_file(optarg);
1616 ca_cert = optarg; 1546 ca_cert = optarg;
1617 goto enable_ssl; 1547 goto enable_ssl;
1618#endif 1548#endif
1619#ifdef LIBCURL_FEATURE_SSL 1549#ifdef LIBCURL_FEATURE_SSL
1620 case 'D': /* verify peer certificate & host */ 1550 case 'D': /* verify peer certificate & host */
1621 verify_peer_and_host = true; 1551 verify_peer_and_host = true;
1622 break; 1552 break;
1623#endif 1553#endif
1624 case 'S': /* use SSL */ 1554 case 'S': /* use SSL */
1625#ifdef LIBCURL_FEATURE_SSL 1555#ifdef LIBCURL_FEATURE_SSL
1626 enable_ssl: 1556 enable_ssl:
1627 use_ssl = true; 1557 use_ssl = true;
1628 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default. 1558 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
1629 * Only set if it's non-zero. This helps when we include multiple 1559 * Only set if it's non-zero. This helps when we include multiple
1630 * parameters, like -S and -C combinations */ 1560 * parameters, like -S and -C combinations */
1631 ssl_version = CURL_SSLVERSION_DEFAULT; 1561 ssl_version = CURL_SSLVERSION_DEFAULT;
1632 if (c=='S' && optarg != NULL) { 1562 if (c == 'S' && optarg != NULL) {
1633 char *plus_ptr = strchr(optarg, '+'); 1563 char *plus_ptr = strchr(optarg, '+');
1634 if (plus_ptr) { 1564 if (plus_ptr) {
1635 got_plus = 1; 1565 got_plus = 1;
1636 *plus_ptr = '\0'; 1566 *plus_ptr = '\0';
1637 } 1567 }
1638 1568
1639 if (optarg[0] == '2') 1569 if (optarg[0] == '2')
1640 ssl_version = CURL_SSLVERSION_SSLv2; 1570 ssl_version = CURL_SSLVERSION_SSLv2;
1641 else if (optarg[0] == '3') 1571 else if (optarg[0] == '3')
1642 ssl_version = CURL_SSLVERSION_SSLv3; 1572 ssl_version = CURL_SSLVERSION_SSLv3;
1643 else if (!strcmp (optarg, "1") || !strcmp (optarg, "1.0")) 1573 else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0"))
1644#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1574# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1645 ssl_version = CURL_SSLVERSION_TLSv1_0; 1575 ssl_version = CURL_SSLVERSION_TLSv1_0;
1646#else 1576# else
1647 ssl_version = CURL_SSLVERSION_DEFAULT; 1577 ssl_version = CURL_SSLVERSION_DEFAULT;
1648#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1578# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1649 else if (!strcmp (optarg, "1.1")) 1579 else if (!strcmp(optarg, "1.1"))
1650#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1580# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1651 ssl_version = CURL_SSLVERSION_TLSv1_1; 1581 ssl_version = CURL_SSLVERSION_TLSv1_1;
1652#else 1582# else
1653 ssl_version = CURL_SSLVERSION_DEFAULT; 1583 ssl_version = CURL_SSLVERSION_DEFAULT;
1654#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1584# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1655 else if (!strcmp (optarg, "1.2")) 1585 else if (!strcmp(optarg, "1.2"))
1656#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1586# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1657 ssl_version = CURL_SSLVERSION_TLSv1_2; 1587 ssl_version = CURL_SSLVERSION_TLSv1_2;
1658#else 1588# else
1659 ssl_version = CURL_SSLVERSION_DEFAULT; 1589 ssl_version = CURL_SSLVERSION_DEFAULT;
1660#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1590# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1661 else if (!strcmp (optarg, "1.3")) 1591 else if (!strcmp(optarg, "1.3"))
1662#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) 1592# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
1663 ssl_version = CURL_SSLVERSION_TLSv1_3; 1593 ssl_version = CURL_SSLVERSION_TLSv1_3;
1664#else 1594# else
1665 ssl_version = CURL_SSLVERSION_DEFAULT; 1595 ssl_version = CURL_SSLVERSION_DEFAULT;
1666#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */ 1596# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
1667 else 1597 else
1668 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)")); 1598 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)"));
1669 } 1599 }
1670#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) 1600# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
1671 if (got_plus) { 1601 if (got_plus) {
1672 switch (ssl_version) { 1602 switch (ssl_version) {
1673 case CURL_SSLVERSION_TLSv1_3: 1603 case CURL_SSLVERSION_TLSv1_3:
1674 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1604 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1675 break; 1605 break;
1676 case CURL_SSLVERSION_TLSv1_2: 1606 case CURL_SSLVERSION_TLSv1_2:
1677 case CURL_SSLVERSION_TLSv1_1: 1607 case CURL_SSLVERSION_TLSv1_1:
1678 case CURL_SSLVERSION_TLSv1_0: 1608 case CURL_SSLVERSION_TLSv1_0:
1679 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT; 1609 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
1680 break; 1610 break;
1681 } 1611 }
1682 } else { 1612 } else {
1683 switch (ssl_version) { 1613 switch (ssl_version) {
1684 case CURL_SSLVERSION_TLSv1_3: 1614 case CURL_SSLVERSION_TLSv1_3:
1685 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1615 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1686 break; 1616 break;
1687 case CURL_SSLVERSION_TLSv1_2: 1617 case CURL_SSLVERSION_TLSv1_2:
1688 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2; 1618 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
1689 break; 1619 break;
1690 case CURL_SSLVERSION_TLSv1_1: 1620 case CURL_SSLVERSION_TLSv1_1:
1691 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1; 1621 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
1692 break; 1622 break;
1693 case CURL_SSLVERSION_TLSv1_0: 1623 case CURL_SSLVERSION_TLSv1_0:
1694 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0; 1624 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
1695 break; 1625 break;
1696 } 1626 }
1697 } 1627 }
1698#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ 1628# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1699 if (verbose >= 2) 1629 if (verbose >= 2)
1700 printf(_("* Set SSL/TLS version to %d\n"), ssl_version); 1630 printf(_("* Set SSL/TLS version to %d\n"), ssl_version);
1701 if (!specify_port) 1631 if (!specify_port)
1702 server_port = HTTPS_PORT; 1632 server_port = HTTPS_PORT;
1703 break; 1633 break;
1704#else /* LIBCURL_FEATURE_SSL */ 1634#else /* LIBCURL_FEATURE_SSL */
1705 /* -C -J and -K fall through to here without SSL */ 1635 /* -C -J and -K fall through to here without SSL */
1706 usage4 (_("Invalid option - SSL is not available")); 1636 usage4(_("Invalid option - SSL is not available"));
1707 break; 1637 break;
1708 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */ 1638 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */
1709 use_sni = true; 1639 use_sni = true;
1710 break; 1640 break;
1711#endif /* LIBCURL_FEATURE_SSL */ 1641#endif /* LIBCURL_FEATURE_SSL */
1712 case MAX_REDIRS_OPTION: 1642 case MAX_REDIRS_OPTION:
1713 if (!is_intnonneg (optarg)) 1643 if (!is_intnonneg(optarg))
1714 usage2 (_("Invalid max_redirs count"), optarg); 1644 usage2(_("Invalid max_redirs count"), optarg);
1715 else { 1645 else {
1716 max_depth = atoi (optarg); 1646 max_depth = atoi(optarg);
1717 } 1647 }
1718 break; 1648 break;
1719 case 'f': /* onredirect */ 1649 case 'f': /* onredirect */
1720 if (!strcmp (optarg, "ok")) 1650 if (!strcmp(optarg, "ok"))
1721 onredirect = STATE_OK; 1651 onredirect = STATE_OK;
1722 else if (!strcmp (optarg, "warning")) 1652 else if (!strcmp(optarg, "warning"))
1723 onredirect = STATE_WARNING; 1653 onredirect = STATE_WARNING;
1724 else if (!strcmp (optarg, "critical")) 1654 else if (!strcmp(optarg, "critical"))
1725 onredirect = STATE_CRITICAL; 1655 onredirect = STATE_CRITICAL;
1726 else if (!strcmp (optarg, "unknown")) 1656 else if (!strcmp(optarg, "unknown"))
1727 onredirect = STATE_UNKNOWN; 1657 onredirect = STATE_UNKNOWN;
1728 else if (!strcmp (optarg, "follow")) 1658 else if (!strcmp(optarg, "follow"))
1729 onredirect = STATE_DEPENDENT; 1659 onredirect = STATE_DEPENDENT;
1730 else if (!strcmp (optarg, "stickyport")) 1660 else if (!strcmp(optarg, "stickyport"))
1731 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST|STICKY_PORT; 1661 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST | STICKY_PORT;
1732 else if (!strcmp (optarg, "sticky")) 1662 else if (!strcmp(optarg, "sticky"))
1733 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST; 1663 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST;
1734 else if (!strcmp (optarg, "follow")) 1664 else if (!strcmp(optarg, "follow"))
1735 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE; 1665 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE;
1736 else if (!strcmp (optarg, "curl")) 1666 else if (!strcmp(optarg, "curl"))
1737 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL; 1667 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL;
1738 else usage2 (_("Invalid onredirect option"), optarg); 1668 else
1739 if (verbose >= 2) 1669 usage2(_("Invalid onredirect option"), optarg);
1740 printf(_("* Following redirects set to %s\n"), state_text(onredirect)); 1670 if (verbose >= 2)
1741 break; 1671 printf(_("* Following redirects set to %s\n"), state_text(onredirect));
1742 case 'd': /* string or substring */ 1672 break;
1743 strncpy (header_expect, optarg, MAX_INPUT_BUFFER - 1); 1673 case 'd': /* string or substring */
1744 header_expect[MAX_INPUT_BUFFER - 1] = 0; 1674 strncpy(header_expect, optarg, MAX_INPUT_BUFFER - 1);
1745 break; 1675 header_expect[MAX_INPUT_BUFFER - 1] = 0;
1746 case 's': /* string or substring */ 1676 break;
1747 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1); 1677 case 's': /* string or substring */
1748 string_expect[MAX_INPUT_BUFFER - 1] = 0; 1678 strncpy(string_expect, optarg, MAX_INPUT_BUFFER - 1);
1749 break; 1679 string_expect[MAX_INPUT_BUFFER - 1] = 0;
1750 case 'e': /* string or substring */ 1680 break;
1751 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1); 1681 case 'e': /* string or substring */
1752 server_expect[MAX_INPUT_BUFFER - 1] = 0; 1682 strncpy(server_expect, optarg, MAX_INPUT_BUFFER - 1);
1753 server_expect_yn = 1; 1683 server_expect[MAX_INPUT_BUFFER - 1] = 0;
1754 break; 1684 server_expect_yn = 1;
1755 case 'T': /* Content-type */ 1685 break;
1756 http_content_type = strdup (optarg); 1686 case 'T': /* Content-type */
1757 break; 1687 http_content_type = strdup(optarg);
1758 case 'l': /* linespan */ 1688 break;
1759 cflags &= ~REG_NEWLINE; 1689 case 'l': /* linespan */
1760 break; 1690 cflags &= ~REG_NEWLINE;
1761 case 'R': /* regex */ 1691 break;
1762 cflags |= REG_ICASE; 1692 case 'R': /* regex */
1693 cflags |= REG_ICASE;
1763 // fall through 1694 // fall through
1764 case 'r': /* regex */ 1695 case 'r': /* regex */
1765 strncpy (regexp, optarg, MAX_RE_SIZE - 1); 1696 strncpy(regexp, optarg, MAX_RE_SIZE - 1);
1766 regexp[MAX_RE_SIZE - 1] = 0; 1697 regexp[MAX_RE_SIZE - 1] = 0;
1767 errcode = regcomp (&preg, regexp, cflags); 1698 errcode = regcomp(&preg, regexp, cflags);
1768 if (errcode != 0) { 1699 if (errcode != 0) {
1769 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1700 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1770 printf (_("Could Not Compile Regular Expression: %s"), errbuf); 1701 printf(_("Could Not Compile Regular Expression: %s"), errbuf);
1771 return false; 1702 return false;
1772 } 1703 }
1773 break; 1704 break;
1774 case INVERT_REGEX: 1705 case INVERT_REGEX:
1775 invert_regex = true; 1706 invert_regex = true;
1776 break; 1707 break;
1777 case STATE_REGEX: 1708 case STATE_REGEX:
1778 if (!strcmp (optarg, "critical")) 1709 if (!strcasecmp(optarg, "critical"))
1779 state_regex = STATE_CRITICAL; 1710 state_regex = STATE_CRITICAL;
1780 else if (!strcmp (optarg, "warning")) 1711 else if (!strcasecmp(optarg, "warning"))
1781 state_regex = STATE_WARNING; 1712 state_regex = STATE_WARNING;
1782 else usage2 (_("Invalid state-regex option"), optarg); 1713 else
1783 break; 1714 usage2(_("Invalid state-regex option"), optarg);
1784 case '4': 1715 break;
1785 address_family = AF_INET; 1716 case '4':
1786 break; 1717 address_family = AF_INET;
1787 case '6': 1718 break;
1788#if defined (USE_IPV6) && defined (LIBCURL_FEATURE_IPV6) 1719 case '6':
1789 address_family = AF_INET6; 1720#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
1721 address_family = AF_INET6;
1790#else 1722#else
1791 usage4 (_("IPv6 support not available")); 1723 usage4(_("IPv6 support not available"));
1792#endif 1724#endif
1793 break; 1725 break;
1794 case 'm': /* min_page_length */ 1726 case 'm': /* min_page_length */
1795 { 1727 {
1796 char *tmp; 1728 char *tmp;
1797 if (strchr(optarg, ':') != (char *)NULL) { 1729 if (strchr(optarg, ':') != (char *)NULL) {
1798 /* range, so get two values, min:max */ 1730 /* range, so get two values, min:max */
1799 tmp = strtok(optarg, ":"); 1731 tmp = strtok(optarg, ":");
1800 if (tmp == NULL) { 1732 if (tmp == NULL) {
1801 printf("Bad format: try \"-m min:max\"\n"); 1733 printf("Bad format: try \"-m min:max\"\n");
1802 exit (STATE_WARNING); 1734 exit(STATE_WARNING);
1803 } else 1735 } else
1804 min_page_len = atoi(tmp); 1736 min_page_len = atoi(tmp);
1805 1737
1806 tmp = strtok(NULL, ":"); 1738 tmp = strtok(NULL, ":");
1807 if (tmp == NULL) { 1739 if (tmp == NULL) {
1808 printf("Bad format: try \"-m min:max\"\n"); 1740 printf("Bad format: try \"-m min:max\"\n");
1809 exit (STATE_WARNING); 1741 exit(STATE_WARNING);
1810 } else 1742 } else
1811 max_page_len = atoi(tmp); 1743 max_page_len = atoi(tmp);
1812 } else 1744 } else
1813 min_page_len = atoi (optarg); 1745 min_page_len = atoi(optarg);
1814 break; 1746 break;
1815 } 1747 }
1816 case 'N': /* no-body */ 1748 case 'N': /* no-body */
1817 no_body = true; 1749 no_body = true;
1818 break; 1750 break;
1819 case 'M': /* max-age */ 1751 case 'M': /* max-age */
1820 { 1752 {
1821 int L = strlen(optarg); 1753 int L = strlen(optarg);
1822 if (L && optarg[L-1] == 'm') 1754 if (L && optarg[L - 1] == 'm')
1823 maximum_age = atoi (optarg) * 60; 1755 maximum_age = atoi(optarg) * 60;
1824 else if (L && optarg[L-1] == 'h') 1756 else if (L && optarg[L - 1] == 'h')
1825 maximum_age = atoi (optarg) * 60 * 60; 1757 maximum_age = atoi(optarg) * 60 * 60;
1826 else if (L && optarg[L-1] == 'd') 1758 else if (L && optarg[L - 1] == 'd')
1827 maximum_age = atoi (optarg) * 60 * 60 * 24; 1759 maximum_age = atoi(optarg) * 60 * 60 * 24;
1828 else if (L && (optarg[L-1] == 's' || 1760 else if (L && (optarg[L - 1] == 's' || isdigit(optarg[L - 1])))
1829 isdigit (optarg[L-1]))) 1761 maximum_age = atoi(optarg);
1830 maximum_age = atoi (optarg); 1762 else {
1831 else { 1763 fprintf(stderr, "unparsable max-age: %s\n", optarg);
1832 fprintf (stderr, "unparsable max-age: %s\n", optarg); 1764 exit(STATE_WARNING);
1833 exit (STATE_WARNING); 1765 }
1834 } 1766 if (verbose >= 2)
1835 if (verbose >= 2) 1767 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); 1768 } break;
1837 } 1769 case 'E': /* show extended perfdata */
1838 break; 1770 show_extended_perfdata = true;
1839 case 'E': /* show extended perfdata */ 1771 break;
1840 show_extended_perfdata = true; 1772 case 'B': /* print body content after status line */
1841 break; 1773 show_body = true;
1842 case 'B': /* print body content after status line */ 1774 break;
1843 show_body = true; 1775 case HTTP_VERSION_OPTION:
1844 break; 1776 curl_http_version = CURL_HTTP_VERSION_NONE;
1845 case HTTP_VERSION_OPTION: 1777 if (strcmp(optarg, "1.0") == 0) {
1846 curl_http_version = CURL_HTTP_VERSION_NONE; 1778 curl_http_version = CURL_HTTP_VERSION_1_0;
1847 if (strcmp (optarg, "1.0") == 0) { 1779 } else if (strcmp(optarg, "1.1") == 0) {
1848 curl_http_version = CURL_HTTP_VERSION_1_0; 1780 curl_http_version = CURL_HTTP_VERSION_1_1;
1849 } else if (strcmp (optarg, "1.1") == 0) { 1781 } 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) 1782#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
1853 curl_http_version = CURL_HTTP_VERSION_2_0; 1783 curl_http_version = CURL_HTTP_VERSION_2_0;
1854#else 1784#else
1855 curl_http_version = CURL_HTTP_VERSION_NONE; 1785 curl_http_version = CURL_HTTP_VERSION_NONE;
1856#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */ 1786#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
1857 } else { 1787 } else {
1858 fprintf (stderr, "unknown http-version parameter: %s\n", optarg); 1788 fprintf(stderr, "unknown http-version parameter: %s\n", optarg);
1859 exit (STATE_WARNING); 1789 exit(STATE_WARNING);
1860 } 1790 }
1861 break; 1791 break;
1862 case AUTOMATIC_DECOMPRESSION: 1792 case AUTOMATIC_DECOMPRESSION:
1863 automatic_decompression = true; 1793 automatic_decompression = true;
1864 break; 1794 break;
1865 case COOKIE_JAR: 1795 case COOKIE_JAR:
1866 cookie_jar_file = optarg; 1796 cookie_jar_file = optarg;
1867 break; 1797 break;
1868 case HAPROXY_PROTOCOL: 1798 case HAPROXY_PROTOCOL:
1869 haproxy_protocol = true; 1799 haproxy_protocol = true;
1870 break; 1800 break;
1871 case '?': 1801 case '?':
1872 /* print short usage statement if args not parsable */ 1802 /* print short usage statement if args not parsable */
1873 usage5 (); 1803 usage5();
1874 break; 1804 break;
1875 } 1805 }
1876 } 1806 }
1877 1807
1878 c = optind; 1808 c = optind;
1879 1809
1880 if (server_address == NULL && c < argc) 1810 if (server_address == NULL && c < argc)
1881 server_address = strdup (argv[c++]); 1811 server_address = strdup(argv[c++]);
1882 1812
1883 if (host_name == NULL && c < argc) 1813 if (host_name == NULL && c < argc)
1884 host_name = strdup (argv[c++]); 1814 host_name = strdup(argv[c++]);
1885 1815
1886 if (server_address == NULL) { 1816 if (server_address == NULL) {
1887 if (host_name == NULL) 1817 if (host_name == NULL)
1888 usage4 (_("You must specify a server address or host name")); 1818 usage4(_("You must specify a server address or host name"));
1889 else 1819 else
1890 server_address = strdup (host_name); 1820 server_address = strdup(host_name);
1891 } 1821 }
1892 1822
1893 set_thresholds(&thlds, warning_thresholds, critical_thresholds); 1823 set_thresholds(&thlds, warning_thresholds, critical_thresholds);
1894 1824
1895 if (critical_thresholds && thlds->critical->end>(double)socket_timeout) 1825 if (critical_thresholds && thlds->critical->end > (double)socket_timeout)
1896 socket_timeout = (int)thlds->critical->end + 1; 1826 socket_timeout = (int)thlds->critical->end + 1;
1897 if (verbose >= 2) 1827 if (verbose >= 2)
1898 printf ("* Socket timeout set to %ld seconds\n", socket_timeout); 1828 printf("* Socket timeout set to %ld seconds\n", socket_timeout);
1899 1829
1900 if (http_method == NULL) 1830 if (http_method == NULL)
1901 http_method = strdup ("GET"); 1831 http_method = strdup("GET");
1902 1832
1903 if (client_cert && !client_privkey) 1833 if (client_cert && !client_privkey)
1904 usage4 (_("If you use a client certificate you must also specify a private key file")); 1834 usage4(_("If you use a client certificate you must also specify a private key file"));
1905 1835
1906 if (virtual_port == 0) 1836 if (virtual_port == 0)
1907 virtual_port = server_port; 1837 virtual_port = server_port;
1908 else { 1838 else {
1909 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT)) 1839 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT))
1910 if(!specify_port) 1840 if (!specify_port)
1911 server_port = virtual_port; 1841 server_port = virtual_port;
1912 } 1842 }
1913 1843
1914 return true; 1844 return true;
1915} 1845}
1916 1846
1917char *perfd_time (double elapsed_time) 1847char *perfd_time(double elapsed_time) {
1918{ 1848 return fperfdata("time", elapsed_time, "s", thlds->warning ? true : false, thlds->warning ? thlds->warning->end : 0,
1919 return fperfdata ("time", elapsed_time, "s", 1849 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} 1850}
1924 1851
1925char *perfd_time_connect (double elapsed_time_connect) 1852char *perfd_time_connect(double elapsed_time_connect) {
1926{ 1853 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} 1854}
1929 1855
1930char *perfd_time_ssl (double elapsed_time_ssl) 1856char *perfd_time_ssl(double elapsed_time_ssl) {
1931{ 1857 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} 1858}
1934 1859
1935char *perfd_time_headers (double elapsed_time_headers) 1860char *perfd_time_headers(double elapsed_time_headers) {
1936{ 1861 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} 1862}
1939 1863
1940char *perfd_time_firstbyte (double elapsed_time_firstbyte) 1864char *perfd_time_firstbyte(double elapsed_time_firstbyte) {
1941{ 1865 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} 1866}
1944 1867
1945char *perfd_time_transfer (double elapsed_time_transfer) 1868char *perfd_time_transfer(double elapsed_time_transfer) {
1946{ 1869 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} 1870}
1949 1871
1950char *perfd_size (int page_len) 1872char *perfd_size(int page_len) {
1951{ 1873 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", 1874 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} 1875}
1957 1876
1958void 1877void print_help(void) {
1959print_help (void) 1878 print_revision(progname, NP_VERSION);
1960{
1961 print_revision (progname, NP_VERSION);
1962 1879
1963 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 1880 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1964 printf (COPYRIGHT, copyright, email); 1881 printf(COPYRIGHT, copyright, email);
1965 1882
1966 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test")); 1883 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")); 1884 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")); 1885 printf("%s\n", _("strings and regular expressions, check connection times, and report on"));
1969 printf ("%s\n", _("certificate expiration times.")); 1886 printf("%s\n", _("certificate expiration times."));
1970 printf ("\n"); 1887 printf("\n");
1971 printf ("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http")); 1888 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.")); 1889 printf("%s\n", _("as possible."));
1973 1890
1974 printf ("\n\n"); 1891 printf("\n\n");
1975 1892
1976 print_usage (); 1893 print_usage();
1977 1894
1978 printf (_("NOTE: One or both of -H and -I must be specified")); 1895 printf(_("NOTE: One or both of -H and -I must be specified"));
1979 1896
1980 printf ("\n"); 1897 printf("\n");
1981 1898
1982 printf (UT_HELP_VRSN); 1899 printf(UT_HELP_VRSN);
1983 printf (UT_EXTRA_OPTS); 1900 printf(UT_EXTRA_OPTS);
1984 1901
1985 printf (" %s\n", "-H, --hostname=ADDRESS"); 1902 printf(" %s\n", "-H, --hostname=ADDRESS");
1986 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)")); 1903 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)")); 1904 printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1988 printf (" %s\n", "-I, --IP-address=ADDRESS"); 1905 printf(" %s\n", "-I, --IP-address=ADDRESS");
1989 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup).")); 1906 printf(" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1990 printf (" %s\n", "-p, --port=INTEGER"); 1907 printf(" %s\n", "-p, --port=INTEGER");
1991 printf (" %s", _("Port number (default: ")); 1908 printf(" %s", _("Port number (default: "));
1992 printf ("%d)\n", HTTP_PORT); 1909 printf("%d)\n", HTTP_PORT);
1993 1910
1994 printf (UT_IPv46); 1911 printf(UT_IPv46);
1995 1912
1996#ifdef LIBCURL_FEATURE_SSL 1913#ifdef LIBCURL_FEATURE_SSL
1997 printf (" %s\n", "-S, --ssl=VERSION[+]"); 1914 printf(" %s\n", "-S, --ssl=VERSION[+]");
1998 printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents")); 1915 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,")); 1916 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.")); 1917 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")); 1918 printf(" %s\n", _("Note: SSLv2, SSLv3, TLSv1.0 and TLSv1.1 are deprecated and are usually disabled in libcurl"));
2002 printf (" %s\n", "--sni"); 1919 printf(" %s\n", "--sni");
2003 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 1920 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
2004#if LIBCURL_VERSION_NUM >= 0x071801 1921# if LIBCURL_VERSION_NUM >= 0x071801
2005 printf (" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and")); 1922 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")); 1923 printf(" %s\n", _(" SNI only really works since TLSv1.0"));
2007#else 1924# else
2008 printf (" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1")); 1925 printf(" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1"));
2009#endif 1926# endif
2010 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]"); 1927 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.")); 1928 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")); 1929 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")); 1930 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.")); 1931 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")); 1932 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)")); 1933 printf(" %s\n", _(" --continue-after-certificate to override this behavior)"));
2017 printf (" %s\n", "--continue-after-certificate"); 1934 printf(" %s\n", "--continue-after-certificate");
2018 printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check.")); 1935 printf(" %s\n", _("Allows the HTTP check to continue after performing the certificate check."));
2019 printf (" %s\n", _("Does nothing unless -C is used.")); 1936 printf(" %s\n", _("Does nothing unless -C is used."));
2020 printf (" %s\n", "-J, --client-cert=FILE"); 1937 printf(" %s\n", "-J, --client-cert=FILE");
2021 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)")); 1938 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")); 1939 printf(" %s\n", _("to be used in establishing the SSL session"));
2023 printf (" %s\n", "-K, --private-key=FILE"); 1940 printf(" %s\n", "-K, --private-key=FILE");
2024 printf (" %s\n", _("Name of file containing the private key (PEM format)")); 1941 printf(" %s\n", _("Name of file containing the private key (PEM format)"));
2025 printf (" %s\n", _("matching the client certificate")); 1942 printf(" %s\n", _("matching the client certificate"));
2026 printf (" %s\n", "--ca-cert=FILE"); 1943 printf(" %s\n", "--ca-cert=FILE");
2027 printf (" %s\n", _("CA certificate file to verify peer against")); 1944 printf(" %s\n", _("CA certificate file to verify peer against"));
2028 printf (" %s\n", "-D, --verify-cert"); 1945 printf(" %s\n", "-D, --verify-cert");
2029 printf (" %s\n", _("Verify the peer's SSL certificate and hostname")); 1946 printf(" %s\n", _("Verify the peer's SSL certificate and hostname"));
2030#endif 1947#endif
2031 1948
2032 printf (" %s\n", "-e, --expect=STRING"); 1949 printf(" %s\n", "-e, --expect=STRING");
2033 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in")); 1950 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: ")); 1951 printf(" %s", _("the first (status) line of the server response (default: "));
2035 printf ("%s)\n", HTTP_EXPECT); 1952 printf("%s)\n", HTTP_EXPECT);
2036 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)")); 1953 printf(" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
2037 printf (" %s\n", "-d, --header-string=STRING"); 1954 printf(" %s\n", "-d, --header-string=STRING");
2038 printf (" %s\n", _("String to expect in the response headers")); 1955 printf(" %s\n", _("String to expect in the response headers"));
2039 printf (" %s\n", "-s, --string=STRING"); 1956 printf(" %s\n", "-s, --string=STRING");
2040 printf (" %s\n", _("String to expect in the content")); 1957 printf(" %s\n", _("String to expect in the content"));
2041 printf (" %s\n", "-u, --url=PATH"); 1958 printf(" %s\n", "-u, --url=PATH");
2042 printf (" %s\n", _("URL to GET or POST (default: /)")); 1959 printf(" %s\n", _("URL to GET or POST (default: /)"));
2043 printf (" %s\n", "-P, --post=STRING"); 1960 printf(" %s\n", "-P, --post=STRING");
2044 printf (" %s\n", _("URL decoded http POST data")); 1961 printf(" %s\n", _("URL decoded http POST data"));
2045 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)"); 1962 printf(" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)");
2046 printf (" %s\n", _("Set HTTP method.")); 1963 printf(" %s\n", _("Set HTTP method."));
2047 printf (" %s\n", "-N, --no-body"); 1964 printf(" %s\n", "-N, --no-body");
2048 printf (" %s\n", _("Don't wait for document body: stop reading after headers.")); 1965 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.)")); 1966 printf(" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
2050 printf (" %s\n", "-M, --max-age=SECONDS"); 1967 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")); 1968 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.")); 1969 printf(" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
2053 printf (" %s\n", "-T, --content-type=STRING"); 1970 printf(" %s\n", "-T, --content-type=STRING");
2054 printf (" %s\n", _("specify Content-Type header media type when POSTing\n")); 1971 printf(" %s\n", _("specify Content-Type header media type when POSTing\n"));
2055 printf (" %s\n", "-l, --linespan"); 1972 printf(" %s\n", "-l, --linespan");
2056 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)")); 1973 printf(" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
2057 printf (" %s\n", "-r, --regex, --ereg=STRING"); 1974 printf(" %s\n", "-r, --regex, --ereg=STRING");
2058 printf (" %s\n", _("Search page for regex STRING")); 1975 printf(" %s\n", _("Search page for regex STRING"));
2059 printf (" %s\n", "-R, --eregi=STRING"); 1976 printf(" %s\n", "-R, --eregi=STRING");
2060 printf (" %s\n", _("Search page for case-insensitive regex STRING")); 1977 printf(" %s\n", _("Search page for case-insensitive regex STRING"));
2061 printf (" %s\n", "--invert-regex"); 1978 printf(" %s\n", "--invert-regex");
2062 printf (" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)")); 1979 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)")); 1980 printf(" %s\n", _("can be changed with --state--regex)"));
2064 printf (" %s\n", "--regex-state=STATE"); 1981 printf(" %s\n", "--state-regex=STATE");
2065 printf (" %s\n", _("Return STATE if regex is found, OK if not\n")); 1982 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"); 1983 printf(" %s\n", "-a, --authorization=AUTH_PAIR");
2067 printf (" %s\n", _("Username:password on sites with basic authentication")); 1984 printf(" %s\n", _("Username:password on sites with basic authentication"));
2068 printf (" %s\n", "-b, --proxy-authorization=AUTH_PAIR"); 1985 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
2069 printf (" %s\n", _("Username:password on proxy-servers with basic authentication")); 1986 printf(" %s\n", _("Username:password on proxy-servers with basic authentication"));
2070 printf (" %s\n", "-A, --useragent=STRING"); 1987 printf(" %s\n", "-A, --useragent=STRING");
2071 printf (" %s\n", _("String to be sent in http header as \"User Agent\"")); 1988 printf(" %s\n", _("String to be sent in http header as \"User Agent\""));
2072 printf (" %s\n", "-k, --header=STRING"); 1989 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")); 1990 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"); 1991 printf(" %s\n", "-E, --extended-perfdata");
2075 printf (" %s\n", _("Print additional performance data")); 1992 printf(" %s\n", _("Print additional performance data"));
2076 printf (" %s\n", "-B, --show-body"); 1993 printf(" %s\n", "-B, --show-body");
2077 printf (" %s\n", _("Print body content below status line")); 1994 printf(" %s\n", _("Print body content below status line"));
2078 printf (" %s\n", "-L, --link"); 1995 printf(" %s\n", "-L, --link");
2079 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)")); 1996 printf(" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
2080 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport|curl>"); 1997 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")); 1998 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.")); 1999 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.")); 2000 printf(" %s\n", _("follow uses the old redirection algorithm of check_http."));
2084 printf (" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl.")); 2001 printf(" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl."));
2085 printf (" %s\n", "--max-redirs=INTEGER"); 2002 printf(" %s\n", "--max-redirs=INTEGER");
2086 printf (" %s", _("Maximal number of redirects (default: ")); 2003 printf(" %s", _("Maximal number of redirects (default: "));
2087 printf ("%d)\n", DEFAULT_MAX_REDIRS); 2004 printf("%d)\n", DEFAULT_MAX_REDIRS);
2088 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); 2005 printf(" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
2089 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); 2006 printf(" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
2090 printf ("\n"); 2007 printf("\n");
2091 printf (" %s\n", "--http-version=VERSION"); 2008 printf(" %s\n", "--http-version=VERSION");
2092 printf (" %s\n", _("Connect via specific HTTP protocol.")); 2009 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)")); 2010 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"); 2011 printf(" %s\n", "--enable-automatic-decompression");
2095 printf (" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING).")); 2012 printf(" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING)."));
2096 printf(" %s\n", "--haproxy-protocol"); 2013 printf(" %s\n", "--haproxy-protocol");
2097 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL).")); 2014 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL)."));
2098 printf (" %s\n", "--cookie-jar=FILE"); 2015 printf(" %s\n", "--cookie-jar=FILE");
2099 printf (" %s\n", _("Store cookies in the cookie jar and send them out when requested.")); 2016 printf(" %s\n", _("Store cookies in the cookie jar and send them out when requested."));
2100 printf ("\n"); 2017 printf(" %s\n", _("Specify an empty string as FILE to enable curl's cookie engine without saving"));
2101 2018 printf(" %s\n", _("the cookies to disk. Only enabling the engine without saving to disk requires"));
2102 printf (UT_WARN_CRIT); 2019 printf(" %s\n", _("handling multiple requests internally to curl, so use it with --onredirect=curl"));
2103 2020 printf("\n");
2104 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 2021
2105 2022 printf(UT_WARN_CRIT);
2106 printf (UT_VERBOSE); 2023
2107 2024 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
2108 printf ("\n"); 2025
2109 printf ("%s\n", _("Notes:")); 2026 printf(UT_VERBOSE);
2110 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host.")); 2027
2111 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL")); 2028 printf("\n");
2112 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response")); 2029 printf("%s\n", _("Notes:"));
2113 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are")); 2030 printf(" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
2114 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN")); 2031 printf(" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
2115 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument.")); 2032 printf(" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response"));
2033 printf(" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
2034 printf(" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
2035 printf(" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
2116 2036
2117#ifdef LIBCURL_FEATURE_SSL 2037#ifdef LIBCURL_FEATURE_SSL
2118 printf ("\n"); 2038 printf("\n");
2119 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to")); 2039 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 ")); 2040 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.")); 2041 printf(" %s\n", _("certificate is still valid for the specified number of days."));
2122 printf ("\n"); 2042 printf("\n");
2123 printf (" %s\n", _("Please note that this plugin does not check if the presented server")); 2043 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")); 2044 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.")); 2045 printf(" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
2126 printf ("\n"); 2046 printf("\n");
2127 printf ("%s\n", _("Examples:")); 2047 printf("%s\n", _("Examples:"));
2128 printf (" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com"); 2048 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,")); 2049 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")); 2050 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,")); 2051 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.")); 2052 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
2133 printf ("\n"); 2053 printf("\n");
2134 printf (" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14"); 2054 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,")); 2055 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")); 2056 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")); 2057 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.")); 2058 printf(" %s\n\n", _("the certificate is expired."));
2139 printf ("\n"); 2059 printf("\n");
2140 printf (" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14"); 2060 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,")); 2061 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")); 2062 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.")); 2063 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")); 2064 printf(" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
2145#endif 2065#endif
2146 2066
2147 printf ("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:"); 2067 printf("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:");
2148 printf (" %s\n", _("It is recommended to use an environment proxy like:")); 2068 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")); 2069 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:")); 2070 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")); 2071 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ -H www.monitoring-plugins.org"));
2152 2072
2153#ifdef LIBCURL_FEATURE_SSL 2073#ifdef LIBCURL_FEATURE_SSL
2154 printf ("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: "); 2074 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:")); 2075 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")); 2076 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:")); 2077 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 ")); 2078 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>")); 2079 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")); 2080 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,")); 2081 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.")); 2082 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
2163 2083
2164#endif 2084#endif
2165 2085
2166 printf (UT_SUPPORT); 2086 printf(UT_SUPPORT);
2167
2168} 2087}
2169 2088
2170 2089void print_usage(void) {
2171 2090 printf("%s\n", _("Usage:"));
2172void 2091 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname);
2173print_usage (void) 2092 printf(" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n");
2174{ 2093 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
2175 printf ("%s\n", _("Usage:")); 2094 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); 2095 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"); 2096 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"); 2097 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"); 2098 printf(" [-T <content-type>] [-j method]\n");
2180 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); 2099 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"); 2100 printf(" [--cookie-jar=<cookie jar file>\n");
2182 printf (" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n"); 2101 printf(" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n", progname);
2183 printf (" [-T <content-type>] [-j method]\n"); 2102 printf(" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
2184 printf (" [--http-version=<version>] [--enable-automatic-decompression]\n"); 2103 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 2104#ifdef LIBCURL_FEATURE_SSL
2190 printf ("%s\n", _("In the first form, make an HTTP request.")); 2105 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.")); 2106 printf("%s\n\n", _("In the second form, connect to the server and check the TLS certificate."));
2192#endif 2107#endif
2193} 2108}
2194 2109
2195void 2110void print_curl_version(void) { printf("%s\n", curl_version()); }
2196print_curl_version (void)
2197{
2198 printf( "%s\n", curl_version());
2199}
2200 2111
2201int 2112int curlhelp_initwritebuffer(curlhelp_write_curlbuf *buf) {
2202curlhelp_initwritebuffer (curlhelp_write_curlbuf *buf) 2113 buf->bufsize = DEFAULT_BUFFER_SIZE;
2203{ 2114 buf->buflen = 0;
2204 buf->bufsize = DEFAULT_BUFFER_SIZE; 2115 buf->buf = (char *)malloc((size_t)buf->bufsize);
2205 buf->buflen = 0; 2116 if (buf->buf == NULL)
2206 buf->buf = (char *)malloc ((size_t)buf->bufsize); 2117 return -1;
2207 if (buf->buf == NULL) return -1; 2118 return 0;
2208 return 0;
2209} 2119}
2210 2120
2211size_t curlhelp_buffer_write_callback (void *buffer, size_t size, size_t nmemb, void *stream) 2121size_t curlhelp_buffer_write_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
2212{ 2122 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
2213 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
2214 2123
2215 while (buf->bufsize < buf->buflen + size * nmemb + 1) { 2124 while (buf->bufsize < buf->buflen + size * nmemb + 1) {
2216 buf->bufsize = buf->bufsize * 2; 2125 buf->bufsize = buf->bufsize * 2;
2217 buf->buf = (char *)realloc (buf->buf, buf->bufsize); 2126 buf->buf = (char *)realloc(buf->buf, buf->bufsize);
2218 if (buf->buf == NULL) { 2127 if (buf->buf == NULL) {
2219 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno)); 2128 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno));
2220 return -1; 2129 return -1;
2221 } 2130 }
2222 } 2131 }
2223 2132
2224 memcpy (buf->buf + buf->buflen, buffer, size * nmemb); 2133 memcpy(buf->buf + buf->buflen, buffer, size * nmemb);
2225 buf->buflen += size * nmemb; 2134 buf->buflen += size * nmemb;
2226 buf->buf[buf->buflen] = '\0'; 2135 buf->buf[buf->buflen] = '\0';
2227 2136
2228 return (int)(size * nmemb); 2137 return (int)(size * nmemb);
2229} 2138}
2230 2139
2231size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) 2140size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
2232{ 2141 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
2233 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
2234 2142
2235 size_t n = min (nmemb * size, buf->buflen - buf->pos); 2143 size_t n = min(nmemb * size, buf->buflen - buf->pos);
2236 2144
2237 memcpy (buffer, buf->buf + buf->pos, n); 2145 memcpy(buffer, buf->buf + buf->pos, n);
2238 buf->pos += n; 2146 buf->pos += n;
2239 2147
2240 return (int)n; 2148 return (int)n;
2241} 2149}
2242 2150
2243void 2151void curlhelp_freewritebuffer(curlhelp_write_curlbuf *buf) {
2244curlhelp_freewritebuffer (curlhelp_write_curlbuf *buf) 2152 free(buf->buf);
2245{ 2153 buf->buf = NULL;
2246 free (buf->buf);
2247 buf->buf = NULL;
2248} 2154}
2249 2155
2250int 2156int curlhelp_initreadbuffer(curlhelp_read_curlbuf *buf, const char *data, size_t datalen) {
2251curlhelp_initreadbuffer (curlhelp_read_curlbuf *buf, const char *data, size_t datalen) 2157 buf->buflen = datalen;
2252{ 2158 buf->buf = (char *)malloc((size_t)buf->buflen);
2253 buf->buflen = datalen; 2159 if (buf->buf == NULL)
2254 buf->buf = (char *)malloc ((size_t)buf->buflen); 2160 return -1;
2255 if (buf->buf == NULL) return -1; 2161 memcpy(buf->buf, data, datalen);
2256 memcpy (buf->buf, data, datalen); 2162 buf->pos = 0;
2257 buf->pos = 0; 2163 return 0;
2258 return 0;
2259} 2164}
2260 2165
2261void 2166void curlhelp_freereadbuffer(curlhelp_read_curlbuf *buf) {
2262curlhelp_freereadbuffer (curlhelp_read_curlbuf *buf) 2167 free(buf->buf);
2263{ 2168 buf->buf = NULL;
2264 free (buf->buf);
2265 buf->buf = NULL;
2266} 2169}
2267 2170
2268/* TODO: where to put this, it's actually part of sstrings2 (logically)? 2171/* TODO: where to put this, it's actually part of sstrings2 (logically)?
2269 */ 2172 */
2270const char* 2173const char *strrstr2(const char *haystack, const char *needle) {
2271strrstr2(const char *haystack, const char *needle) 2174 int counter;
2272{ 2175 size_t len;
2273 int counter; 2176 const char *prev_pos;
2274 size_t len; 2177 const char *pos;
2275 const char *prev_pos; 2178
2276 const char *pos; 2179 if (haystack == NULL || needle == NULL)
2277 2180 return NULL;
2278 if (haystack == NULL || needle == NULL) 2181
2279 return NULL; 2182 if (haystack[0] == '\0' || needle[0] == '\0')
2280 2183 return NULL;
2281 if (haystack[0] == '\0' || needle[0] == '\0') 2184
2282 return NULL; 2185 counter = 0;
2283 2186 prev_pos = NULL;
2284 counter = 0; 2187 pos = haystack;
2285 prev_pos = NULL; 2188 len = strlen(needle);
2286 pos = haystack; 2189 for (;;) {
2287 len = strlen (needle); 2190 pos = strstr(pos, needle);
2288 for (;;) { 2191 if (pos == NULL) {
2289 pos = strstr (pos, needle); 2192 if (counter == 0)
2290 if (pos == NULL) { 2193 return NULL;
2291 if (counter == 0) 2194 return prev_pos;
2292 return NULL; 2195 }
2293 else 2196 counter++;
2294 return prev_pos; 2197 prev_pos = pos;
2295 } 2198 pos += len;
2296 counter++; 2199 if (*pos == '\0')
2297 prev_pos = pos; 2200 return prev_pos;
2298 pos += len; 2201 }
2299 if (*pos == '\0') return prev_pos;
2300 }
2301} 2202}
2302 2203
2303int 2204int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) {
2304curlhelp_parse_statusline (const char *buf, curlhelp_statusline *status_line) 2205 char *first_line_end;
2305{ 2206 char *p;
2306 char *first_line_end; 2207 size_t first_line_len;
2307 char *p; 2208 char *pp;
2308 size_t first_line_len; 2209 const char *start;
2309 char *pp; 2210 char *first_line_buf;
2310 const char *start; 2211
2311 char *first_line_buf; 2212 /* find last start of a new header */
2312 2213 start = strrstr2(buf, "\r\nHTTP/");
2313 /* find last start of a new header */ 2214 if (start != NULL) {
2314 start = strrstr2 (buf, "\r\nHTTP/"); 2215 start += 2;
2315 if (start != NULL) { 2216 buf = start;
2316 start += 2; 2217 }
2317 buf = start;
2318 }
2319
2320 first_line_end = strstr(buf, "\r\n");
2321 if (first_line_end == NULL) return -1;
2322
2323 first_line_len = (size_t)(first_line_end - buf);
2324 status_line->first_line = (char *)malloc (first_line_len + 1);
2325 if (status_line->first_line == NULL) return -1;
2326 memcpy (status_line->first_line, buf, first_line_len);
2327 status_line->first_line[first_line_len] = '\0';
2328 first_line_buf = strdup( status_line->first_line );
2329
2330 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
2331
2332 p = strtok(first_line_buf, "/");
2333 if( p == NULL ) { free( first_line_buf ); return -1; }
2334 if( strcmp( p, "HTTP" ) != 0 ) { free( first_line_buf ); return -1; }
2335
2336 p = strtok( NULL, " " );
2337 if( p == NULL ) { free( first_line_buf ); return -1; }
2338 if( strchr( p, '.' ) != NULL ) {
2339
2340 /* HTTP 1.x case */
2341 strtok( p, "." );
2342 status_line->http_major = (int)strtol( p, &pp, 10 );
2343 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2344 strtok( NULL, " " );
2345 status_line->http_minor = (int)strtol( p, &pp, 10 );
2346 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2347 p += 4; /* 1.x SP */
2348 } else {
2349 /* HTTP 2 case */
2350 status_line->http_major = (int)strtol( p, &pp, 10 );
2351 status_line->http_minor = 0;
2352 p += 2; /* 2 SP */
2353 }
2354
2355 /* status code: "404" or "404.1", then SP */
2356
2357 p = strtok( p, " " );
2358 if( p == NULL ) { free( first_line_buf ); return -1; }
2359 if( strchr( p, '.' ) != NULL ) {
2360 char *ppp;
2361 ppp = strtok( p, "." );
2362 status_line->http_code = (int)strtol( ppp, &pp, 10 );
2363 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2364 ppp = strtok( NULL, "" );
2365 status_line->http_subcode = (int)strtol( ppp, &pp, 10 );
2366 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2367 p += 6; /* 400.1 SP */
2368 } else {
2369 status_line->http_code = (int)strtol( p, &pp, 10 );
2370 status_line->http_subcode = -1;
2371 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2372 p += 4; /* 400 SP */
2373 }
2374
2375 /* Human readable message: "Not Found" CRLF */
2376
2377 p = strtok( p, "" );
2378 if( p == NULL ) { status_line->msg = ""; return 0; }
2379 status_line->msg = status_line->first_line + ( p - first_line_buf );
2380 free( first_line_buf );
2381
2382 return 0;
2383}
2384 2218
2385void 2219 first_line_end = strstr(buf, "\r\n");
2386curlhelp_free_statusline (curlhelp_statusline *status_line) 2220 if (first_line_end == NULL)
2387{ 2221 return -1;
2388 free (status_line->first_line); 2222
2389} 2223 first_line_len = (size_t)(first_line_end - buf);
2224 status_line->first_line = (char *)malloc(first_line_len + 1);
2225 if (status_line->first_line == NULL)
2226 return -1;
2227 memcpy(status_line->first_line, buf, first_line_len);
2228 status_line->first_line[first_line_len] = '\0';
2229 first_line_buf = strdup(status_line->first_line);
2230
2231 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
2232
2233 p = strtok(first_line_buf, "/");
2234 if (p == NULL) {
2235 free(first_line_buf);
2236 return -1;
2237 }
2238 if (strcmp(p, "HTTP") != 0) {
2239 free(first_line_buf);
2240 return -1;
2241 }
2242
2243 p = strtok(NULL, " ");
2244 if (p == NULL) {
2245 free(first_line_buf);
2246 return -1;
2247 }
2248 if (strchr(p, '.') != NULL) {
2249
2250 /* HTTP 1.x case */
2251 strtok(p, ".");
2252 status_line->http_major = (int)strtol(p, &pp, 10);
2253 if (*pp != '\0') {
2254 free(first_line_buf);
2255 return -1;
2256 }
2257 strtok(NULL, " ");
2258 status_line->http_minor = (int)strtol(p, &pp, 10);
2259 if (*pp != '\0') {
2260 free(first_line_buf);
2261 return -1;
2262 }
2263 p += 4; /* 1.x SP */
2264 } else {
2265 /* HTTP 2 case */
2266 status_line->http_major = (int)strtol(p, &pp, 10);
2267 status_line->http_minor = 0;
2268 p += 2; /* 2 SP */
2269 }
2390 2270
2391void 2271 /* status code: "404" or "404.1", then SP */
2392remove_newlines (char *s)
2393{
2394 char *p;
2395 2272
2396 for (p = s; *p != '\0'; p++) 2273 p = strtok(p, " ");
2397 if (*p == '\r' || *p == '\n') 2274 if (p == NULL) {
2398 *p = ' '; 2275 free(first_line_buf);
2276 return -1;
2277 }
2278 if (strchr(p, '.') != NULL) {
2279 char *ppp;
2280 ppp = strtok(p, ".");
2281 status_line->http_code = (int)strtol(ppp, &pp, 10);
2282 if (*pp != '\0') {
2283 free(first_line_buf);
2284 return -1;
2285 }
2286 ppp = strtok(NULL, "");
2287 status_line->http_subcode = (int)strtol(ppp, &pp, 10);
2288 if (*pp != '\0') {
2289 free(first_line_buf);
2290 return -1;
2291 }
2292 p += 6; /* 400.1 SP */
2293 } else {
2294 status_line->http_code = (int)strtol(p, &pp, 10);
2295 status_line->http_subcode = -1;
2296 if (*pp != '\0') {
2297 free(first_line_buf);
2298 return -1;
2299 }
2300 p += 4; /* 400 SP */
2301 }
2302
2303 /* Human readable message: "Not Found" CRLF */
2304
2305 p = strtok(p, "");
2306 if (p == NULL) {
2307 status_line->msg = "";
2308 return 0;
2309 }
2310 status_line->msg = status_line->first_line + (p - first_line_buf);
2311 free(first_line_buf);
2312
2313 return 0;
2399} 2314}
2400 2315
2401char * 2316void curlhelp_free_statusline(curlhelp_statusline *status_line) { free(status_line->first_line); }
2402get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header) 2317
2403{ 2318char *get_header_value(const struct phr_header *headers, const size_t nof_headers, const char *header) {
2404 for(size_t i = 0; i < nof_headers; i++ ) { 2319 for (size_t i = 0; i < nof_headers; i++) {
2405 if(headers[i].name != NULL && strncasecmp( header, headers[i].name, max( headers[i].name_len, 4 ) ) == 0 ) { 2320 if (headers[i].name != NULL && strncasecmp(header, headers[i].name, max(headers[i].name_len, 4)) == 0) {
2406 return strndup( headers[i].value, headers[i].value_len ); 2321 return strndup(headers[i].value, headers[i].value_len);
2407 } 2322 }
2408 } 2323 }
2409 return NULL; 2324 return NULL;
2410} 2325}
2411 2326
2412int 2327int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE]) {
2413check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE]) 2328 char *server_date = NULL;
2414{ 2329 char *document_date = NULL;
2415 char *server_date = NULL; 2330 int date_result = STATE_OK;
2416 char *document_date = NULL; 2331 curlhelp_statusline status_line;
2417 int date_result = STATE_OK; 2332 struct phr_header headers[255];
2418 curlhelp_statusline status_line; 2333 size_t nof_headers = 255;
2419 struct phr_header headers[255]; 2334 size_t msglen;
2420 size_t nof_headers = 255; 2335
2421 size_t msglen; 2336 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
2422 2337 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
2423 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
2424 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
2425 headers, &nof_headers, 0);
2426 2338
2427 if (res == -1) { 2339 if (res == -1) {
2428 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2340 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2429 } 2341 }
2430 2342
2431 server_date = get_header_value (headers, nof_headers, "date"); 2343 server_date = get_header_value(headers, nof_headers, "date");
2432 document_date = get_header_value (headers, nof_headers, "last-modified"); 2344 document_date = get_header_value(headers, nof_headers, "last-modified");
2433 2345
2434 if (!server_date || !*server_date) { 2346 if (!server_date || !*server_date) {
2435 char tmp[DEFAULT_BUFFER_SIZE]; 2347 char tmp[DEFAULT_BUFFER_SIZE];
2436 2348
2437 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg); 2349 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg);
2438 strcpy(*msg, tmp); 2350 strcpy(*msg, tmp);
2439 2351
2440 date_result = max_state_alt(STATE_UNKNOWN, date_result); 2352 date_result = max_state_alt(STATE_UNKNOWN, date_result);
@@ -2442,34 +2354,34 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
2442 } else if (!document_date || !*document_date) { 2354 } else if (!document_date || !*document_date) {
2443 char tmp[DEFAULT_BUFFER_SIZE]; 2355 char tmp[DEFAULT_BUFFER_SIZE];
2444 2356
2445 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg); 2357 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg);
2446 strcpy(*msg, tmp); 2358 strcpy(*msg, tmp);
2447 2359
2448 date_result = max_state_alt(STATE_CRITICAL, date_result); 2360 date_result = max_state_alt(STATE_CRITICAL, date_result);
2449 2361
2450 } else { 2362 } else {
2451 time_t srv_data = curl_getdate (server_date, NULL); 2363 time_t srv_data = curl_getdate(server_date, NULL);
2452 time_t doc_data = curl_getdate (document_date, NULL); 2364 time_t doc_data = curl_getdate(document_date, NULL);
2453 if (verbose >= 2) 2365 if (verbose >= 2)
2454 printf ("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data); 2366 printf("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data);
2455 if (srv_data <= 0) { 2367 if (srv_data <= 0) {
2456 char tmp[DEFAULT_BUFFER_SIZE]; 2368 char tmp[DEFAULT_BUFFER_SIZE];
2457 2369
2458 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date); 2370 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
2459 strcpy(*msg, tmp); 2371 strcpy(*msg, tmp);
2460 2372
2461 date_result = max_state_alt(STATE_CRITICAL, date_result); 2373 date_result = max_state_alt(STATE_CRITICAL, date_result);
2462 } else if (doc_data <= 0) { 2374 } else if (doc_data <= 0) {
2463 char tmp[DEFAULT_BUFFER_SIZE]; 2375 char tmp[DEFAULT_BUFFER_SIZE];
2464 2376
2465 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date); 2377 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
2466 strcpy(*msg, tmp); 2378 strcpy(*msg, tmp);
2467 2379
2468 date_result = max_state_alt(STATE_CRITICAL, date_result); 2380 date_result = max_state_alt(STATE_CRITICAL, date_result);
2469 } else if (doc_data > srv_data + 30) { 2381 } else if (doc_data > srv_data + 30) {
2470 char tmp[DEFAULT_BUFFER_SIZE]; 2382 char tmp[DEFAULT_BUFFER_SIZE];
2471 2383
2472 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data); 2384 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data);
2473 strcpy(*msg, tmp); 2385 strcpy(*msg, tmp);
2474 2386
2475 date_result = max_state_alt(STATE_CRITICAL, date_result); 2387 date_result = max_state_alt(STATE_CRITICAL, date_result);
@@ -2478,14 +2390,14 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
2478 if (n > (60 * 60 * 24 * 2)) { 2390 if (n > (60 * 60 * 24 * 2)) {
2479 char tmp[DEFAULT_BUFFER_SIZE]; 2391 char tmp[DEFAULT_BUFFER_SIZE];
2480 2392
2481 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24)); 2393 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float)n) / (60 * 60 * 24));
2482 strcpy(*msg, tmp); 2394 strcpy(*msg, tmp);
2483 2395
2484 date_result = max_state_alt(STATE_CRITICAL, date_result); 2396 date_result = max_state_alt(STATE_CRITICAL, date_result);
2485 } else { 2397 } else {
2486 char tmp[DEFAULT_BUFFER_SIZE]; 2398 char tmp[DEFAULT_BUFFER_SIZE];
2487 2399
2488 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60); 2400 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60);
2489 strcpy(*msg, tmp); 2401 strcpy(*msg, tmp);
2490 2402
2491 date_result = max_state_alt(STATE_CRITICAL, date_result); 2403 date_result = max_state_alt(STATE_CRITICAL, date_result);
@@ -2493,132 +2405,128 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
2493 } 2405 }
2494 } 2406 }
2495 2407
2496 if (server_date) free (server_date); 2408 if (server_date)
2497 if (document_date) free (document_date); 2409 free(server_date);
2410 if (document_date)
2411 free(document_date);
2498 2412
2499 return date_result; 2413 return date_result;
2500} 2414}
2501 2415
2416int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf) {
2417 size_t content_length = 0;
2418 struct phr_header headers[255];
2419 size_t nof_headers = 255;
2420 size_t msglen;
2421 char *content_length_s = NULL;
2422 curlhelp_statusline status_line;
2502 2423
2503int 2424 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
2504get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_write_curlbuf* body_buf) 2425 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
2505{
2506 size_t content_length = 0;
2507 struct phr_header headers[255];
2508 size_t nof_headers = 255;
2509 size_t msglen;
2510 char *content_length_s = NULL;
2511 curlhelp_statusline status_line;
2512
2513 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
2514 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
2515 headers, &nof_headers, 0);
2516 2426
2517 if (res == -1) { 2427 if (res == -1) {
2518 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2428 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2519 } 2429 }
2520 2430
2521 content_length_s = get_header_value (headers, nof_headers, "content-length"); 2431 content_length_s = get_header_value(headers, nof_headers, "content-length");
2522 if (!content_length_s) { 2432 if (!content_length_s) {
2523 return header_buf->buflen + body_buf->buflen; 2433 return header_buf->buflen + body_buf->buflen;
2524 } 2434 }
2525 content_length_s += strspn (content_length_s, " \t"); 2435 content_length_s += strspn(content_length_s, " \t");
2526 content_length = atoi (content_length_s); 2436 content_length = atoi(content_length_s);
2527 if (content_length != body_buf->buflen) { 2437 if (content_length != body_buf->buflen) {
2528 /* TODO: should we warn if the actual and the reported body length don't match? */ 2438 /* TODO: should we warn if the actual and the reported body length don't match? */
2529 } 2439 }
2530 2440
2531 if (content_length_s) free (content_length_s); 2441 if (content_length_s)
2442 free(content_length_s);
2532 2443
2533 return header_buf->buflen + body_buf->buflen; 2444 return header_buf->buflen + body_buf->buflen;
2534} 2445}
2535 2446
2536/* TODO: is there a better way in libcurl to check for the SSL library? */ 2447/* TODO: is there a better way in libcurl to check for the SSL library? */
2537curlhelp_ssl_library 2448curlhelp_ssl_library curlhelp_get_ssl_library(void) {
2538curlhelp_get_ssl_library () 2449 curl_version_info_data *version_data;
2539{ 2450 char *ssl_version;
2540 curl_version_info_data* version_data; 2451 char *library;
2541 char *ssl_version; 2452 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
2542 char *library; 2453
2543 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; 2454 version_data = curl_version_info(CURLVERSION_NOW);
2544 2455 if (version_data == NULL)
2545 version_data = curl_version_info (CURLVERSION_NOW); 2456 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2546 if (version_data == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN; 2457
2547 2458 ssl_version = strdup(version_data->ssl_version);
2548 ssl_version = strdup (version_data->ssl_version); 2459 if (ssl_version == NULL)
2549 if (ssl_version == NULL ) return CURLHELP_SSL_LIBRARY_UNKNOWN; 2460 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2550 2461
2551 library = strtok (ssl_version, "/"); 2462 library = strtok(ssl_version, "/");
2552 if (library == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN; 2463 if (library == NULL)
2553 2464 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2554 if (strcmp (library, "OpenSSL") == 0) 2465
2555 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL; 2466 if (strcmp(library, "OpenSSL") == 0)
2556 else if (strcmp (library, "LibreSSL") == 0) 2467 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL;
2557 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL; 2468 else if (strcmp(library, "LibreSSL") == 0)
2558 else if (strcmp (library, "GnuTLS") == 0) 2469 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL;
2559 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS; 2470 else if (strcmp(library, "GnuTLS") == 0)
2560 else if (strcmp (library, "NSS") == 0) 2471 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS;
2561 ssl_library = CURLHELP_SSL_LIBRARY_NSS; 2472 else if (strcmp(library, "NSS") == 0)
2562 2473 ssl_library = CURLHELP_SSL_LIBRARY_NSS;
2563 if (verbose >= 2) 2474
2564 printf ("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library); 2475 if (verbose >= 2)
2565 2476 printf("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library);
2566 free (ssl_version); 2477
2567 2478 free(ssl_version);
2568 return ssl_library; 2479
2480 return ssl_library;
2569} 2481}
2570 2482
2571const char* 2483const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library ssl_library) {
2572curlhelp_get_ssl_library_string (curlhelp_ssl_library ssl_library) 2484 switch (ssl_library) {
2573{ 2485 case CURLHELP_SSL_LIBRARY_OPENSSL:
2574 switch (ssl_library) { 2486 return "OpenSSL";
2575 case CURLHELP_SSL_LIBRARY_OPENSSL: 2487 case CURLHELP_SSL_LIBRARY_LIBRESSL:
2576 return "OpenSSL"; 2488 return "LibreSSL";
2577 case CURLHELP_SSL_LIBRARY_LIBRESSL: 2489 case CURLHELP_SSL_LIBRARY_GNUTLS:
2578 return "LibreSSL"; 2490 return "GnuTLS";
2579 case CURLHELP_SSL_LIBRARY_GNUTLS: 2491 case CURLHELP_SSL_LIBRARY_NSS:
2580 return "GnuTLS"; 2492 return "NSS";
2581 case CURLHELP_SSL_LIBRARY_NSS: 2493 case CURLHELP_SSL_LIBRARY_UNKNOWN:
2582 return "NSS"; 2494 default:
2583 case CURLHELP_SSL_LIBRARY_UNKNOWN: 2495 return "unknown";
2584 default: 2496 }
2585 return "unknown";
2586 }
2587} 2497}
2588 2498
2589#ifdef LIBCURL_FEATURE_SSL 2499#ifdef LIBCURL_FEATURE_SSL
2590#ifndef USE_OPENSSL 2500# ifndef USE_OPENSSL
2591time_t 2501time_t parse_cert_date(const char *s) {
2592parse_cert_date (const char *s) 2502 struct tm tm;
2593{ 2503 time_t date;
2594 struct tm tm; 2504 char *res;
2595 time_t date; 2505
2596 char *res; 2506 if (!s)
2597 2507 return -1;
2598 if (!s) return -1; 2508
2599 2509 /* Jan 17 14:25:12 2020 GMT */
2600 /* Jan 17 14:25:12 2020 GMT */ 2510 res = strptime(s, "%Y-%m-%d %H:%M:%S GMT", &tm);
2601 res = strptime (s, "%Y-%m-%d %H:%M:%S GMT", &tm); 2511 /* Sep 11 12:00:00 2020 GMT */
2602 /* Sep 11 12:00:00 2020 GMT */ 2512 if (res == NULL)
2603 if (res == NULL) strptime (s, "%Y %m %d %H:%M:%S GMT", &tm); 2513 strptime(s, "%Y %m %d %H:%M:%S GMT", &tm);
2604 date = mktime (&tm); 2514 date = mktime(&tm);
2605 2515
2606 return date; 2516 return date;
2607} 2517}
2608 2518
2609/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to 2519/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to
2610 * OpenSSL could be this function 2520 * OpenSSL could be this function
2611 */ 2521 */
2612int 2522int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_warn, int days_till_exp_crit) {
2613net_noopenssl_check_certificate (cert_ptr_union* cert_ptr, int days_till_exp_warn, int days_till_exp_crit) 2523 int i;
2614{ 2524 struct curl_slist *slist;
2615 int i; 2525 int cname_found = 0;
2616 struct curl_slist* slist; 2526 char *start_date_str = NULL;
2617 int cname_found = 0; 2527 char *end_date_str = NULL;
2618 char* start_date_str = NULL; 2528 time_t start_date;
2619 char* end_date_str = NULL; 2529 time_t end_date;
2620 time_t start_date;
2621 time_t end_date;
2622 char *tz; 2530 char *tz;
2623 float time_left; 2531 float time_left;
2624 int days_left; 2532 int days_left;
@@ -2626,66 +2534,64 @@ net_noopenssl_check_certificate (cert_ptr_union* cert_ptr, int days_till_exp_war
2626 char timestamp[50] = ""; 2534 char timestamp[50] = "";
2627 int status = STATE_UNKNOWN; 2535 int status = STATE_UNKNOWN;
2628 2536
2629 if (verbose >= 2) 2537 if (verbose >= 2)
2630 printf ("**** REQUEST CERTIFICATES ****\n"); 2538 printf("**** REQUEST CERTIFICATES ****\n");
2631 2539
2632 for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) { 2540 for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) {
2633 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) { 2541 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) {
2634 /* find first common name in subject, 2542 /* find first common name in subject,
2635 * TODO: check alternative subjects for 2543 * TODO: check alternative subjects for
2636 * TODO: have a decent parser here and not a hack 2544 * TODO: have a decent parser here and not a hack
2637 * multi-host certificate, check wildcards 2545 * multi-host certificate, check wildcards
2638 */ 2546 */
2639 if (strncasecmp (slist->data, "Subject:", 8) == 0) { 2547 if (strncasecmp(slist->data, "Subject:", 8) == 0) {
2640 int d = 3; 2548 int d = 3;
2641 char* p = strstr (slist->data, "CN="); 2549 char *p = strstr(slist->data, "CN=");
2642 if (p == NULL) { 2550 if (p == NULL) {
2643 d = 5; 2551 d = 5;
2644 p = strstr (slist->data, "CN = "); 2552 p = strstr(slist->data, "CN = ");
2645 } 2553 }
2646 if (p != NULL) { 2554 if (p != NULL) {
2647 if (strncmp (host_name, p+d, strlen (host_name)) == 0) { 2555 if (strncmp(host_name, p + d, strlen(host_name)) == 0) {
2648 cname_found = 1; 2556 cname_found = 1;
2649 } 2557 }
2650 } 2558 }
2651 } else if (strncasecmp (slist->data, "Start Date:", 11) == 0) { 2559 } else if (strncasecmp(slist->data, "Start Date:", 11) == 0) {
2652 start_date_str = &slist->data[11]; 2560 start_date_str = &slist->data[11];
2653 } else if (strncasecmp (slist->data, "Expire Date:", 12) == 0) { 2561 } else if (strncasecmp(slist->data, "Expire Date:", 12) == 0) {
2654 end_date_str = &slist->data[12]; 2562 end_date_str = &slist->data[12];
2655 } else if (strncasecmp (slist->data, "Cert:", 5) == 0) { 2563 } else if (strncasecmp(slist->data, "Cert:", 5) == 0) {
2656 goto HAVE_FIRST_CERT; 2564 goto HAVE_FIRST_CERT;
2657 } 2565 }
2658 if (verbose >= 2) 2566 if (verbose >= 2)
2659 printf ("%d ** %s\n", i, slist->data); 2567 printf("%d ** %s\n", i, slist->data);
2660 } 2568 }
2661 } 2569 }
2662HAVE_FIRST_CERT: 2570HAVE_FIRST_CERT:
2663 2571
2664 if (verbose >= 2) 2572 if (verbose >= 2)
2665 printf ("**** REQUEST CERTIFICATES ****\n"); 2573 printf("**** REQUEST CERTIFICATES ****\n");
2666 2574
2667 if (!cname_found) { 2575 if (!cname_found) {
2668 printf("%s\n",_("CRITICAL - Cannot retrieve certificate subject.")); 2576 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
2669 return STATE_CRITICAL; 2577 return STATE_CRITICAL;
2670 } 2578 }
2671 2579
2672 start_date = parse_cert_date (start_date_str); 2580 start_date = parse_cert_date(start_date_str);
2673 if (start_date <= 0) { 2581 if (start_date <= 0) {
2674 snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), 2582 snprintf(msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), start_date_str);
2675 start_date_str); 2583 puts(msg);
2676 puts (msg); 2584 return STATE_WARNING;
2677 return STATE_WARNING; 2585 }
2678 } 2586
2679 2587 end_date = parse_cert_date(end_date_str);
2680 end_date = parse_cert_date (end_date_str); 2588 if (end_date <= 0) {
2681 if (end_date <= 0) { 2589 snprintf(msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), start_date_str);
2682 snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), 2590 puts(msg);
2683 start_date_str); 2591 return STATE_WARNING;
2684 puts (msg); 2592 }
2685 return STATE_WARNING; 2593
2686 } 2594 time_left = difftime(end_date, time(NULL));
2687
2688 time_left = difftime (end_date, time(NULL));
2689 days_left = time_left / 86400; 2595 days_left = time_left / 86400;
2690 tz = getenv("TZ"); 2596 tz = getenv("TZ");
2691 setenv("TZ", "GMT", 1); 2597 setenv("TZ", "GMT", 1);
@@ -2698,30 +2604,31 @@ HAVE_FIRST_CERT:
2698 tzset(); 2604 tzset();
2699 2605
2700 if (days_left > 0 && days_left <= days_till_exp_warn) { 2606 if (days_left > 0 && days_left <= days_till_exp_warn) {
2701 printf (_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", host_name, days_left, timestamp); 2607 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL",
2608 host_name, days_left, timestamp);
2702 if (days_left > days_till_exp_crit) 2609 if (days_left > days_till_exp_crit)
2703 status = STATE_WARNING; 2610 status = STATE_WARNING;
2704 else 2611 else
2705 status = STATE_CRITICAL; 2612 status = STATE_CRITICAL;
2706 } else if (days_left == 0 && time_left > 0) { 2613 } else if (days_left == 0 && time_left > 0) {
2707 if (time_left >= 3600) 2614 if (time_left >= 3600)
2708 time_remaining = (int) time_left / 3600; 2615 time_remaining = (int)time_left / 3600;
2709 else 2616 else
2710 time_remaining = (int) time_left / 60; 2617 time_remaining = (int)time_left / 60;
2711 2618
2712 printf (_("%s - Certificate '%s' expires in %u %s (%s)\n"), 2619 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name,
2713 (days_left>days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, time_remaining, 2620 time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp);
2714 time_left >= 3600 ? "hours" : "minutes", timestamp);
2715 2621
2716 if ( days_left > days_till_exp_crit) 2622 if (days_left > days_till_exp_crit)
2717 status = STATE_WARNING; 2623 status = STATE_WARNING;
2718 else 2624 else
2719 status = STATE_CRITICAL; 2625 status = STATE_CRITICAL;
2720 } else if (time_left < 0) { 2626 } else if (time_left < 0) {
2721 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp); 2627 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp);
2722 status=STATE_CRITICAL; 2628 status = STATE_CRITICAL;
2723 } else if (days_left == 0) { 2629 } else if (days_left == 0) {
2724 printf (_("%s - Certificate '%s' just expired (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", host_name, timestamp); 2630 printf(_("%s - Certificate '%s' just expired (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name,
2631 timestamp);
2725 if (days_left > days_till_exp_crit) 2632 if (days_left > days_till_exp_crit)
2726 status = STATE_WARNING; 2633 status = STATE_WARNING;
2727 else 2634 else
@@ -2732,5 +2639,5 @@ HAVE_FIRST_CERT:
2732 } 2639 }
2733 return status; 2640 return status;
2734} 2641}
2735#endif /* USE_OPENSSL */ 2642# endif /* USE_OPENSSL */
2736#endif /* LIBCURL_FEATURE_SSL */ 2643#endif /* LIBCURL_FEATURE_SSL */