summaryrefslogtreecommitdiffstats
path: root/plugins/check_curl.c
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2017-01-19 10:23:00 +0100
committerSven Nierlein <sven@nierlein.de>2018-10-22 16:28:51 +0200
commit2a9812ee43d64d11be96544f84501686541da86b (patch)
treed302ea1127a09f31a9ba82915b6ca7b53da2aab0 /plugins/check_curl.c
parent0b85260bd2d6b2fd62588c71daf44bc1156a632f (diff)
downloadmonitoring-plugins-2a9812ee43d64d11be96544f84501686541da86b.tar.gz
added most options from nagios-curl-plugin
Diffstat (limited to 'plugins/check_curl.c')
-rw-r--r--plugins/check_curl.c658
1 files changed, 640 insertions, 18 deletions
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index be024feb..e4230dc4 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -40,6 +40,20 @@ const char *email = "devel@monitoring-plugins.org";
40#include "common.h" 40#include "common.h"
41#include "utils.h" 41#include "utils.h"
42 42
43#ifdef HAVE_SYS_TYPES_H
44#include <sys/types.h>
45#else
46#define unsigned int size_t
47#endif
48
49#ifdef HAVE_STRING_H
50#include <string.h>
51#endif
52
53#ifdef HAVE_STDLIB_H
54#include <stdlib.h>
55#endif
56
43#ifndef LIBCURL_PROTOCOL_HTTP 57#ifndef LIBCURL_PROTOCOL_HTTP
44#error libcurl compiled without HTTP support, compiling check_curl plugin makes not much sense 58#error libcurl compiled without HTTP support, compiling check_curl plugin makes not much sense
45#endif 59#endif
@@ -47,50 +61,343 @@ const char *email = "devel@monitoring-plugins.org";
47#include "curl/curl.h" 61#include "curl/curl.h"
48#include "curl/easy.h" 62#include "curl/easy.h"
49 63
50int verbose = FALSE; 64#define DEFAULT_BUFFER_SIZE 2048
65#define DEFAULT_SERVER_URL "/"
66#define DEFAULT_HTTP_PORT 80
67#define DEFAULT_HTTPS_PORT 443
68#define MAX_PORT 65535
69
70/* for buffers for header and body */
71typedef struct {
72 char *buf;
73 size_t buflen;
74 size_t bufsize;
75} curlhelp_curlbuf;
76
77/* for parsing the HTTP status line */
78typedef struct {
79 int http_major; /* major version of the protocol, always 1 (HTTP/0.9
80 * never reached the big internet most likely) */
81 int http_minor; /* minor version of the protocol, usually 0 or 1 */
82 int http_code; /* HTTP return code as in RFC 2145 */
83 int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see
84 * http://support.microsoft.com/kb/318380/en-us */
85 char *msg; /* the human readable message */
86 char *first_line; /* a copy of the first line */
87} curlhelp_statusline;
88
89char *server_address;
90char *host_name;
91char *server_url = DEFAULT_SERVER_URL;
92unsigned short server_port = DEFAULT_HTTP_PORT;
93char *warning_thresholds = NULL;
94char *critical_thresholds = NULL;
95thresholds *thlds;
96char user_agent[DEFAULT_BUFFER_SIZE];
97int verbose = 0;
51CURL *curl; 98CURL *curl;
99struct curl_slist *header_list = NULL;
100curlhelp_curlbuf body_buf;
101curlhelp_curlbuf header_buf;
102curlhelp_statusline status_line;
103char http_header[DEFAULT_BUFFER_SIZE];
104long code;
105long socket_timeout = DEFAULT_SOCKET_TIMEOUT;
106double total_time;
107char errbuf[CURL_ERROR_SIZE+1];
108CURLcode res;
109char url[DEFAULT_BUFFER_SIZE];
110char msg[DEFAULT_BUFFER_SIZE];
111char perfstring[DEFAULT_BUFFER_SIZE];
112char user_auth[MAX_INPUT_BUFFER] = "";
113int onredirect = STATE_OK;
114int use_ssl = FALSE;
115int use_sni = TRUE;
116int check_cert = FALSE;
117int ssl_version = CURL_SSLVERSION_DEFAULT;
118char *client_cert = NULL;
119char *client_privkey = NULL;
52 120
53int process_arguments (int, char **); 121int process_arguments (int, char**);
54void print_help (void); 122void print_help (void);
55void print_usage (void); 123void print_usage (void);
56void print_curl_version (void); 124void print_curl_version (void);
125int curlhelp_initbuffer (curlhelp_curlbuf*);
126int curlhelp_buffer_callback (void*, size_t , size_t , void*);
127void curlhelp_freebuffer (curlhelp_curlbuf*);
128
129int curlhelp_parse_statusline (char*, curlhelp_statusline *);
130void curlhelp_free_statusline (curlhelp_statusline *);
131
132void remove_newlines (char *);
133void test_file (char *);
57 134
58int 135int
59main (int argc, char **argv) 136main (int argc, char **argv)
60{ 137{
61 int result = STATE_UNKNOWN; 138 int result = STATE_OK;
62 139
63 setlocale (LC_ALL, ""); 140 setlocale (LC_ALL, "");
64 bindtextdomain (PACKAGE, LOCALEDIR); 141 bindtextdomain (PACKAGE, LOCALEDIR);
65 textdomain (PACKAGE); 142 textdomain (PACKAGE);
66 143
67 /* Parse extra opts if any */ 144 /* Parse extra opts if any */
68 argv=np_extra_opts (&argc, argv, progname); 145 argv = np_extra_opts (&argc, argv, progname);
146
147 /* set defaults */
148 snprintf( user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s)",
149 progname, NP_VERSION, VERSION);
69 150
151 /* parse arguments */
70 if (process_arguments (argc, argv) == ERROR) 152 if (process_arguments (argc, argv) == ERROR)
71 usage4 (_("Could not parse arguments")); 153 usage4 (_("Could not parse arguments"));
72 154
155 /* initialize curl */
73 if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK) 156 if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK)
74 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n"); 157 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
75 158
76 if ((curl = curl_easy_init()) == NULL) 159 if ((curl = curl_easy_init()) == NULL)
77 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n"); 160 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n");
78 161
162 if (verbose >= 3)
163 curl_easy_setopt (curl, CURLOPT_VERBOSE, TRUE);
164
165 /* initialize buffer for body of the answer */
166 if (curlhelp_initbuffer(&body_buf) < 0)
167 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
168 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, curlhelp_buffer_callback);
169 curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *)&body_buf);
170
171 /* initialize buffer for header of the answer */
172 if (curlhelp_initbuffer( &header_buf ) < 0)
173 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n" );
174 curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, curlhelp_buffer_callback);
175 curl_easy_setopt (curl, CURLOPT_WRITEHEADER, (void *)&header_buf);
176
177 /* set the error buffer */
178 curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, errbuf);
179
180 /* set timeouts */
181 curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, socket_timeout);
182 curl_easy_setopt (curl, CURLOPT_TIMEOUT, socket_timeout);
183
184 /* compose URL */
185 snprintf (url, DEFAULT_BUFFER_SIZE, "%s://%s%s", use_ssl ? "https" : "http",
186 server_address, server_url);
187 curl_easy_setopt (curl, CURLOPT_URL, url);
188
189 /* set port */
190 curl_easy_setopt (curl, CURLOPT_PORT, server_port);
191
192 /* compose HTTP headers */
193 snprintf (http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name);
194 header_list = curl_slist_append (header_list, http_header);
195 curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list );
196
197 /* set SSL version, warn about unsecure or unsupported versions */
198 if (use_ssl) {
199 curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version);
200 }
201
202 /* client certificate and key to present to server (SSL) */
203 if (client_cert)
204 curl_easy_setopt (curl, CURLOPT_SSLCERT, client_cert);
205 if (client_privkey)
206 curl_easy_setopt (curl, CURLOPT_SSLKEY, client_privkey);
207
208 /* per default if we have a CA verify both the peer and the
209 * hostname in the certificate, can be switched off later */
210 curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 2);
211 curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2);
212
213 /* backward-compatible behaviour, be tolerant in checks */
214 if (!check_cert) {
215 //TODO: depending on more options have aspects we want
216 //to be tolerant about
217 //curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 1 );
218 curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0);
219 curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0);
220 }
221
222 /* set default or user-given user agent identification */
223 curl_easy_setopt (curl, CURLOPT_USERAGENT, user_agent);
224
225 /* authentication */
226 if (strcmp(user_auth, ""))
227 curl_easy_setopt (curl, CURLOPT_USERPWD, user_auth);
228
229 /* TODO: parameter auth method, bitfield of following methods:
230 * CURLAUTH_BASIC (default)
231 * CURLAUTH_DIGEST
232 * CURLAUTH_DIGEST_IE
233 * CURLAUTH_NEGOTIATE
234 * CURLAUTH_NTLM
235 * CURLAUTH_NTLM_WB
236 *
237 * convenience tokens for typical sets of methods:
238 * CURLAUTH_ANYSAFE: most secure, without BASIC
239 * or CURLAUTH_ANY: most secure, even BASIC if necessary
240 *
241 * curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST );
242 */
243
244 /* TODO: --cacert: CA certificate file to verify SSL connection against (SSL) */
245 //~ if( args_info.cacert_given ) {
246 //~ curl_easy_setopt( curl, CURLOPT_CAINFO, args_info.cacert_arg );
247 //~ }
248
249 /* TODO: old option -s: check if the excepted string matches */
250 //~ if( args_info.string_given ) {
251 //~ if( strstr( body_buf.buf, args_info.string_arg ) == NULL ) {
252 //~ printf( "HTTP CRITICAL - string not found|%s\n", perfstring );
253 //~ curl_easy_cleanup( curl );
254 //~ curl_global_cleanup( );
255 //~ curlhelp_freebuffer( &body_buf );
256 //~ curlhelp_freebuffer( &header_buf );
257 //~ exit( STATE_CRITICAL );
258 //~ }
259 //~ }
260
261 /* handle redirections */
262 if (onredirect == STATE_DEPENDENT) {
263 curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1);
264 /* TODO: handle the following aspects of redirection
265 CURLOPT_POSTREDIR: method switch
266 CURLINFO_REDIRECT_URL: custom redirect option
267 CURLOPT_REDIRECT_PROTOCOLS
268 CURLINFO_REDIRECT_COUNT
269 */
270 }
271
272 /* do the request */
273 res = curl_easy_perform(curl);
274
275 /* free header list, we don't need it anymore */
276 curl_slist_free_all (header_list);
277
278 /* Curl errors, result in critical Nagios state */
279 if (res != CURLE_OK) {
280 remove_newlines (errbuf);
281 snprintf (msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: %s\n"),
282 server_port, status_line.msg, status_line.msg);
283 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", errbuf);
284 }
285
286 /* we got the data and we executed the request in a given time, so we can append
287 * performance data to the answer always
288 */
289 curl_easy_getinfo (curl, CURLINFO_TOTAL_TIME, &total_time);
290 snprintf (perfstring, DEFAULT_BUFFER_SIZE, "time=%.6gs;%.6g;%.6g;%.6g size=%dB;;;0",
291 total_time,
292 0.0, 0.0,
293 //~ args_info.warning_given ? args_info.warning_arg : 0.0,
294 //~ args_info.critical_given ? args_info.critical_arg : 0.0,
295 0.0,
296 (int)body_buf.buflen);
297
298 /* return a CRITICAL status if we couldn't read any data */
299 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0)
300 die (STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
301
302 /* get status line of answer, check sanity of HTTP code */
303 if (curlhelp_parse_statusline (header_buf.buf, &status_line) < 0) {
304 snprintf (msg, DEFAULT_BUFFER_SIZE, "Unparseable status line in %.3g seconds response time|%s\n",
305 code, total_time, perfstring);
306 die (STATE_CRITICAL, "HTTP CRITICAL HTTP/1.x %d unknown - %s", code, msg);
307 }
308
309 /* get result code from cURL */
310 curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &code);
311 if (verbose>=2)
312 printf ("* curl CURLINFO_RESPONSE_CODE is %d\n", code);
313
314 /* print status line, header, body if verbose */
315 if (verbose >= 2) {
316 puts ("--- HEADER ---");
317 puts (header_buf.buf);
318 puts ("--- BODY ---");
319 puts (body_buf.buf);
320 }
321
322 /* illegal return codes result in a critical state */
323 if (code >= 600 || code < 100) {
324 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg);
325 /* server errors result in a critical state */
326 } else if (code >= 500) {
327 result = STATE_CRITICAL;
328 /* client errors result in a warning state */
329 } else if (code >= 400) {
330 result = STATE_WARNING;
331 /* check redirected page if specified */
332 } else if (code >= 300) {
333 if (onredirect == STATE_DEPENDENT) {
334 code = status_line.http_code;
335 }
336 result = max_state_alt (onredirect, result);
337 // TODO: make sure the last status line has been
338 // parsed into the status_line structure
339 /* all other codes are considered ok */
340 } else {
341 result = STATE_OK;
342 }
343
344 /* check status codes, set exit status accordingly */
345 if( status_line.http_code != code ) {
346 die (STATE_CRITICAL, _("HTTP CRITICAL HTTP/%d.%d %d %s - different HTTP codes (cUrl has %ld)\n"),
347 status_line.http_major, status_line.http_minor,
348 status_line.http_code, status_line.msg, code);
349 }
350
351 /* -w, -c: check warning and critical level */
352 result = max_state_alt(get_status(total_time, thlds), result);
353
354 //~ die (result, "HTTP %s: %s\n", state_text(result), msg);
355 die (result, "HTTP %s HTTP/%d.%d %d %s - %.3g seconds response time|%s\n",
356 state_text(result), status_line.http_major, status_line.http_minor,
357 status_line.http_code, status_line.msg,
358 total_time, perfstring);
359
360 /* proper cleanup after die? */
361 curlhelp_free_statusline(&status_line);
79 curl_easy_cleanup (curl); 362 curl_easy_cleanup (curl);
80 curl_global_cleanup (); 363 curl_global_cleanup ();
81 364 curlhelp_freebuffer(&body_buf);
365 curlhelp_freebuffer(&header_buf);
366
82 return result; 367 return result;
83} 368}
84 369
370/* check whether a file exists */
371void
372test_file (char *path)
373{
374 if (access(path, R_OK) == 0)
375 return;
376 usage2 (_("file does not exist or is not readable"), path);
377}
378
85int 379int
86process_arguments (int argc, char **argv) 380process_arguments (int argc, char **argv)
87{ 381{
88 int c; 382 int c;
383
384 enum {
385 SNI_OPTION
386 };
387
89 int option=0; 388 int option=0;
90 static struct option longopts[] = { 389 static struct option longopts[] = {
91 {"version", no_argument, 0, 'V'}, 390 {"ssl", optional_argument, 0, 'S'},
92 {"help", no_argument, 0, 'h'}, 391 {"sni", no_argument, 0, SNI_OPTION},
93 {"verbose", no_argument, 0, 'v'}, 392 {"IP-address", required_argument, 0, 'I'},
393 {"url", required_argument, 0, 'u'},
394 {"port", required_argument, 0, 'p'},
395 {"authorization", required_argument, 0, 'a'},
396 {"onredirect", required_argument, 0, 'f'},
397 {"client-cert", required_argument, 0, 'J'},
398 {"private-key", required_argument, 0, 'K'},
399 {"useragent", required_argument, 0, 'A'},
400 {"certificate", required_argument, 0, 'C'},
94 {0, 0, 0, 0} 401 {0, 0, 0, 0}
95 }; 402 };
96 403
@@ -98,7 +405,7 @@ process_arguments (int argc, char **argv)
98 usage ("\n"); 405 usage ("\n");
99 406
100 while (1) { 407 while (1) {
101 c = getopt_long (argc, argv, "Vhv", longopts, &option); 408 c = getopt_long (argc, argv, "Vvht:c:w:A:H:I:a:p:u:f:C:J:K:S::", longopts, &option);
102 if (c == -1 || c == EOF || c == 1) 409 if (c == -1 || c == EOF || c == 1)
103 break; 410 break;
104 411
@@ -115,14 +422,155 @@ process_arguments (int argc, char **argv)
115 case 'v': 422 case 'v':
116 verbose++; 423 verbose++;
117 break; 424 break;
425 case 't': /* timeout period */
426 if (!is_intnonneg (optarg))
427 usage2 (_("Timeout interval must be a positive integer"), optarg);
428 else
429 socket_timeout = (int)strtol (optarg, NULL, 10);
430 break;
431 case 'c': /* critical time threshold */
432 critical_thresholds = optarg;
433 break;
434 case 'w': /* warning time threshold */
435 warning_thresholds = optarg;
436 break;
437 case 'H': /* virtual host */
438 host_name = strdup (optarg);
439 break;
440 case 'I': /* internet address */
441 server_address = strdup (optarg);
442 break;
443 case 'u': /* URL path */
444 server_url = strdup (optarg);
445 break;
446 case 'p': /* Server port */
447 if (!is_intnonneg (optarg))
448 usage2 (_("Invalid port number, expecting a non-negative number"), optarg);
449 else {
450 if( strtol(optarg, NULL, 10) > MAX_PORT)
451 usage2 (_("Invalid port number, supplied port number is too big"), optarg);
452 server_port = (unsigned short)strtol(optarg, NULL, 10);
453 }
454 break;
455 case 'a': /* authorization info */
456 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
457 user_auth[MAX_INPUT_BUFFER - 1] = 0;
458 break;
459 case 'A': /* useragent */
460 snprintf (user_agent, DEFAULT_BUFFER_SIZE, optarg);
461 break;
462 case 'C': /* Check SSL cert validity */
463#ifdef LIBCURL_FEATURE_SSL
464 /* TODO: C:, check age of certificate for backward compatible
465 * behaviour, but we would later add more check conditions */
466 check_cert = TRUE;
467 goto enable_ssl;
468#endif
469 case 'J': /* use client certificate */
470#ifdef LIBCURL_FEATURE_SSL
471 test_file(optarg);
472 client_cert = optarg;
473 goto enable_ssl;
474#endif
475 case 'K': /* use client private key */
476#ifdef LIBCURL_FEATURE_SSL
477 test_file(optarg);
478 client_privkey = optarg;
479 goto enable_ssl;
480#endif
481 case 'S': /* use SSL */
482#ifdef LIBCURL_FEATURE_SSL
483 enable_ssl:
484 use_ssl = TRUE;
485 /* ssl_version initialized to CURL_SSLVERSION_TLSv1_0 as a default. Only set if it's non-zero. This helps when we include multiple
486 parameters, like -S and -C combinations */
487 ssl_version = CURL_SSLVERSION_TLSv1_0;
488 if (c=='S' && optarg != NULL) {
489 int got_plus = strchr(optarg, '+') != NULL;
490
491 if (!strncmp (optarg, "1.2", 3))
492 ssl_version = CURL_SSLVERSION_TLSv1_2;
493 else if (!strncmp (optarg, "1.1", 3))
494 ssl_version = CURL_SSLVERSION_TLSv1_1;
495 else if (optarg[0] == '1')
496 ssl_version = CURL_SSLVERSION_TLSv1_0;
497 else if (optarg[0] == '3')
498 ssl_version = CURL_SSLVERSION_SSLv3;
499 else if (optarg[0] == '2')
500 ssl_version = CURL_SSLVERSION_SSLv2;
501 else
502 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with optional '+' suffix)"));
503 }
504 if (server_port == DEFAULT_HTTP_PORT)
505 server_port = DEFAULT_HTTPS_PORT;
506#else
507 /* -C -J and -K fall through to here without SSL */
508 usage4 (_("Invalid option - SSL is not available"));
509#endif
510 break;
511 case SNI_OPTION: /* --sni is parsed, but ignored, the default is TRUE with libcurl */
512 use_sni = TRUE;
513 break;
514 case 'f': /* onredirect */
515 if (!strcmp (optarg, "ok"))
516 onredirect = STATE_OK;
517 else if (!strcmp (optarg, "warning"))
518 onredirect = STATE_WARNING;
519 else if (!strcmp (optarg, "critical"))
520 onredirect = STATE_CRITICAL;
521 else if (!strcmp (optarg, "unknown"))
522 onredirect = STATE_UNKNOWN;
523 else if (!strcmp (optarg, "follow"))
524 onredirect = STATE_DEPENDENT;
525 else usage2 (_("Invalid onredirect option"), optarg);
526 //~ if (!strcmp (optarg, "stickyport"))
527 //~ onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT;
528 //~ else if (!strcmp (optarg, "sticky"))
529 //~ onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST;
530 //~ else if (!strcmp (optarg, "follow"))
531 //~ onredirect = STATE_DEPENDENT, followsticky = STICKY_NONE;
532 if (verbose >= 2)
533 printf(_("* Following redirects set to %s\n"), state_text(onredirect));
534 break;
118 case '?': 535 case '?':
119 /* print short usage statement if args not parsable */ 536 /* print short usage statement if args not parsable */
120 usage5 (); 537 usage5 ();
121 break; 538 break;
122 } 539 }
123 } 540 }
541
542 c = optind;
124 543
125 return 0; 544 if (server_address == NULL && c < argc)
545 server_address = strdup (argv[c++]);
546
547 if (host_name == NULL && c < argc)
548 host_name = strdup (argv[c++]);
549
550 if (server_address == NULL) {
551 if (host_name == NULL)
552 usage4 (_("You must specify a server address or host name"));
553 else
554 server_address = strdup (host_name);
555 }
556
557 set_thresholds(&thlds, warning_thresholds, critical_thresholds);
558
559 if (critical_thresholds && thlds->critical->end>(double)socket_timeout)
560 socket_timeout = (int)thlds->critical->end + 1;
561 if (verbose >= 2)
562 printf ("* Socket timeout set to %d seconds\n", socket_timeout);
563
564 //~ if (http_method == NULL)
565 //~ http_method = strdup ("GET");
566
567 if (client_cert && !client_privkey)
568 usage4 (_("If you use a client certificate you must also specify a private key file"));
569
570 //~ if (virtual_port == 0)
571 //~ virtual_port = server_port;
572
573 return TRUE;
126} 574}
127 575
128void 576void
@@ -133,32 +581,91 @@ print_help (void)
133 printf ("Copyright (c) 2017 Andreas Baumann <abaumann@yahoo.com>\n"); 581 printf ("Copyright (c) 2017 Andreas Baumann <abaumann@yahoo.com>\n");
134 printf (COPYRIGHT, copyright, email); 582 printf (COPYRIGHT, copyright, email);
135 583
136 printf ("%s\n", _("This plugin tests the HTTP(S) service on the specified host.")); 584 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
137 printf ("%s\n", _("It makes use of libcurl to do so.")); 585 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
586 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
587 printf ("%s\n", _("certificate expiration times."));
588 printf ("\n");
589 printf ("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http"));
590 printf ("%s\n", _("as possible."));
138 591
139 printf ("\n\n"); 592 printf ("\n\n");
140 593
141 print_usage(); 594 print_usage();
595
142 printf (_("NOTE: One or both of -H and -I must be specified")); 596 printf (_("NOTE: One or both of -H and -I must be specified"));
143 597
144 printf ("\n"); 598 printf ("\n");
145 599
146 printf (UT_HELP_VRSN); 600 printf (UT_HELP_VRSN);
601 printf (UT_EXTRA_OPTS);
602
603 printf (" %s\n", "-H, --hostname=ADDRESS");
604 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
605 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
606 printf (" %s\n", "-I, --IP-address=ADDRESS");
607 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
608 printf (" %s\n", "-p, --port=INTEGER");
609 printf (" %s", _("Port number (default: "));
610 printf ("%d)\n", DEFAULT_HTTP_PORT);
611
612#ifdef LIBCURL_FEATURE_SSL
613 printf (" %s\n", "-S, --ssl=VERSION[+]");
614 printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
615 printf (" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,"));
616 printf (" %s\n", _("1.2 = TLSv1.2). With a '+' suffix, newer versions are also accepted."));
617 printf (" %s\n", _("Note: SSLv2 and SSLv3 are deprecated and are usually disabled in libcurl"));
618 printf (" %s\n", "--sni");
619 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
620#if LIBCURL_VERSION_NUM >= 0x071801
621 printf (" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and"));
622 printf (" %s\n", _(" SNI only really works since TLSv1.0"));
623#else
624 printf (" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1"));
625#endif
626 printf (" %s\n", "-C, --certificate");
627 printf (" %s\n", _("Check validity of certificate"));
628 printf (" %s\n", "-J, --client-cert=FILE");
629 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)"));
630 printf (" %s\n", _("to be used in establishing the SSL session"));
631 printf (" %s\n", "-K, --private-key=FILE");
632 printf (" %s\n", _("Name of file containing the private key (PEM format)"));
633 printf (" %s\n", _("matching the client certificate"));
634#endif
635
636 printf (" %s\n", "-u, --url=PATH");
637 printf (" %s\n", _("URL to GET or POST (default: /)"));
638
639 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
640 printf (" %s\n", _("Username:password on sites with basic authentication"));
641 printf (" %s\n", "-A, --useragent=STRING");
642 printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
643 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>");
644 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
645 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
646
647 printf (UT_WARN_CRIT);
648
649 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
650
147 printf (UT_VERBOSE); 651 printf (UT_VERBOSE);
148 652
149 printf (UT_SUPPORT); 653 printf (UT_SUPPORT);
150
151 printf ("%s\n", _("WARNING: check_curl is experimental. Please use"));
152 printf ("%s\n\n", _("check_http if you need a stable version."));
153} 654}
154 655
155void 656void
156print_usage (void) 657print_usage (void)
157{ 658{
659 printf ("%s\n", _("Usage:"));
660 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
661 printf (" [-J <client certificate file>] [-K <private key>]\n");
662 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-a auth]\n");
663 printf (" [-f <ok|warning|critcal|follow>]\n");
664 printf (" [-A string] [-S <version>] [-C]\n");
665 printf (" [-v verbose]\n", progname);
666 printf ("\n");
158 printf ("%s\n", _("WARNING: check_curl is experimental. Please use")); 667 printf ("%s\n", _("WARNING: check_curl is experimental. Please use"));
159 printf ("%s\n\n", _("check_http if you need a stable version.")); 668 printf ("%s\n\n", _("check_http if you need a stable version."));
160 printf ("%s\n", _("Usage:"));
161 printf (" %s [-v verbose]\n", progname);
162} 669}
163 670
164void 671void
@@ -166,3 +673,118 @@ print_curl_version (void)
166{ 673{
167 printf( "%s\n", curl_version()); 674 printf( "%s\n", curl_version());
168} 675}
676
677int
678curlhelp_initbuffer (curlhelp_curlbuf *buf)
679{
680 buf->bufsize = DEFAULT_BUFFER_SIZE;
681 buf->buflen = 0;
682 buf->buf = (char *)malloc ((size_t)buf->bufsize);
683 if (buf->buf == NULL) return -1;
684 return 0;
685}
686
687int
688curlhelp_buffer_callback (void *buffer, size_t size, size_t nmemb, void *stream)
689{
690 curlhelp_curlbuf *buf = (curlhelp_curlbuf *)stream;
691
692 while (buf->bufsize < buf->buflen + size * nmemb + 1) {
693 buf->bufsize *= buf->bufsize * 2;
694 buf->buf = (char *)realloc (buf->buf, buf->bufsize);
695 if (buf->buf == NULL) return -1;
696 }
697
698 memcpy (buf->buf + buf->buflen, buffer, size * nmemb);
699 buf->buflen += size * nmemb;
700 buf->buf[buf->buflen] = '\0';
701
702 return (int)(size * nmemb);
703}
704
705void
706curlhelp_freebuffer (curlhelp_curlbuf *buf)
707{
708 free (buf->buf);
709 buf->buf = NULL;
710}
711
712/* TODO: when redirecting we get more than one HTTP header, make sure
713 * we parse the last one
714 */
715int
716curlhelp_parse_statusline (char *buf, curlhelp_statusline *status_line)
717{
718 char *first_line_end;
719 char *p;
720 size_t first_line_len;
721 char *pp;
722
723 first_line_end = strstr(buf, "\r\n");
724 if (first_line_end == NULL) return -1;
725
726 first_line_len = (size_t)(first_line_end - buf);
727 status_line->first_line = (char *)malloc (first_line_len + 1);
728 if (status_line->first_line == NULL) return -1;
729 memcpy (status_line->first_line, buf, first_line_len);
730 status_line->first_line[first_line_len] = '\0';
731
732 /* protocol and version: "HTTP/x.x" SP */
733
734 p = strtok(status_line->first_line, "/");
735 if( p == NULL ) { free( status_line->first_line ); return -1; }
736 if( strcmp( p, "HTTP" ) != 0 ) { free( status_line->first_line ); return -1; }
737
738 p = strtok( NULL, "." );
739 if( p == NULL ) { free( status_line->first_line ); return -1; }
740 status_line->http_major = (int)strtol( p, &pp, 10 );
741 if( *pp != '\0' ) { free( status_line->first_line ); return -1; }
742
743 p = strtok( NULL, " " );
744 if( p == NULL ) { free( status_line->first_line ); return -1; }
745 status_line->http_minor = (int)strtol( p, &pp, 10 );
746 if( *pp != '\0' ) { free( status_line->first_line ); return -1; }
747
748 /* status code: "404" or "404.1", then SP */
749
750 p = strtok( NULL, " ." );
751 if( p == NULL ) { free( status_line->first_line ); return -1; }
752 if( strchr( p, '.' ) != NULL ) {
753 char *ppp;
754 ppp = strtok( p, "." );
755 status_line->http_code = (int)strtol( ppp, &pp, 10 );
756 if( *pp != '\0' ) { free( status_line->first_line ); return -1; }
757
758 ppp = strtok( NULL, "" );
759 status_line->http_subcode = (int)strtol( ppp, &pp, 10 );
760 if( *pp != '\0' ) { free( status_line->first_line ); return -1; }
761 } else {
762 status_line->http_code = (int)strtol( p, &pp, 10 );
763 status_line->http_subcode = -1;
764 if( *pp != '\0' ) { free( status_line->first_line ); return -1; }
765 }
766
767 /* Human readable message: "Not Found" CRLF */
768
769 p = strtok( NULL, "" );
770 if( p == NULL ) { free( status_line->first_line ); return -1; }
771 status_line->msg = p;
772
773 return 0;
774}
775
776void
777curlhelp_free_statusline (curlhelp_statusline *status_line)
778{
779 free (status_line->first_line);
780}
781
782void
783remove_newlines (char *s)
784{
785 char *p;
786
787 for (p = s; *p != '\0'; p++)
788 if (*p == '\r' || *p == '\n')
789 *p = ' ';
790}