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