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