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