/*
check_curl - Nagios Curl-based check plugin
Copyright (C) 2008 Andreas Baumann
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include /* for printf */
#include /* for exit */
#include /* for strstr */
#include
#include
#include "cmdline.h"
#include "common.h"
#include "curlhelper.h"
#include "utils.h"
#define DEFAULT_TIMEOUT (double)10.0
int main( int argc, char *argv[] ) {
struct gengetopt_args_info args_info;
curlhelp_curlbuf body_buf;
curlhelp_curlbuf header_buf;
CURL *curl;
char b[2048];
char b2[2048];
CURLcode res;
char errbuf[CURL_ERROR_SIZE+1];
struct curl_slist *header_list = NULL;
long code;
double total_time;
const char *level_str = "OK";
int exit_state = STATE_OK;
char perfstring[1024];
curlhelp_statusline status_line;
const char *protocol;
const char *answer_protocol;
cmdline_parser_init( &args_info );
/* read command line arguments (to get the name of the configuration file,
* do it without checking for required arguments
*/
if( cmdline_parser2( argc, argv, &args_info, 0, 0, 0 ) != 0 ) {
printf( "HTTP CRITICAL - unable to parse arguments\n" );
fprintf( stderr, "\n%s\n", gengetopt_args_info_usage );
cmdline_parser_free( &args_info );
exit( STATE_UNKNOWN );
}
if( args_info.config_file_given ) {
/* read command line options from file, allow override of configuration
* options from the command line and check for required options
*/
if( cmdline_parser_configfile( args_info.config_file_arg, &args_info, 1, 0, 1 ) != 0 ) {
printf( "HTTP CRITICAL - unable to read '%s'\n", args_info.config_file_arg );
fprintf( stderr, "\n%s\n", gengetopt_args_info_usage );
cmdline_parser_free( &args_info );
exit( STATE_UNKNOWN );
}
} else {
/* read command line options again, this time checking for required options */
if( cmdline_parser2( argc, argv, &args_info, 1, 0, 1 ) != 0 ) {
printf( "HTTP CRITICAL - illegal arguments, check help page\n" );
fprintf( stderr, "\n%s\n", gengetopt_args_info_usage );
cmdline_parser_free( &args_info );
exit( STATE_UNKNOWN );
}
}
/* start up curl */
if( curl_global_init( (long)CURL_GLOBAL_ALL ) != CURLE_OK ) {
printf( "HTTP CRITICAL - curl_global_init failed!\n" );
cmdline_parser_free( &args_info );
exit( STATE_UNKNOWN );
}
if( ( curl = curl_easy_init( ) ) == NULL ) {
printf( "HTTP CRITICAL - curl_easy_init failed!\n" );
cmdline_parser_free( &args_info );
curl_global_cleanup( );
exit( STATE_UNKNOWN );
}
/* -v: verbosity */
curl_easy_setopt( curl, CURLOPT_VERBOSE, args_info.verbose_given );
/* initialize buffer for body of the answer */
if( curlhelp_initbuffer( &body_buf ) < 0 ) {
printf( "HTTP CRITICAL - out of memory allocating a buffer\n" );
cmdline_parser_free( &args_info );
curl_global_cleanup( );
exit( STATE_UNKNOWN );
}
curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, curlhelp_buffer_callback );
curl_easy_setopt( curl, CURLOPT_WRITEDATA, (void *)&body_buf );
/* initialize buffer for header of the answer */
if( curlhelp_initbuffer( &header_buf ) < 0 ) {
printf( "HTTP CRITICAL - out of memory allocating a buffer\n" );
curlhelp_freebuffer( &body_buf );
cmdline_parser_free( &args_info );
curl_global_cleanup( );
exit( STATE_UNKNOWN );
}
curl_easy_setopt( curl, CURLOPT_HEADERFUNCTION, curlhelp_buffer_callback );
curl_easy_setopt( curl, CURLOPT_WRITEHEADER , (void *)&header_buf );
/* authentication */
if( args_info.authorization_given )
curl_easy_setopt( curl, CURLOPT_USERPWD, args_info.authorization_arg );
/* -d: digest */
if( args_info.digest_given )
curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST );
/* user agent */
if( args_info.useragent_given )
curl_easy_setopt( curl, CURLOPT_USERAGENT, args_info.useragent_arg );
/* --protocol: currently tested http and ftp */
if( !args_info.protocol_given )
protocol = "http";
else
protocol = args_info.protocol_arg;
/* compose URL */
snprintf( b, (size_t)2048, "%s%s://%s%s",
protocol,
args_info.ssl_given ? "s" : "",
args_info.ip_arg,
args_info.url_given ? args_info.url_arg : "/" );
curl_easy_setopt( curl, CURLOPT_URL, b );
/* -S (SSL) */
if( args_info.ssl_given && strcmp( protocol, "ftp" ) == 0 ) {
curl_easy_setopt( curl, CURLOPT_FTP_SSL, 0 );
curl_easy_setopt( curl, CURLOPT_SSLVERSION, 0 );
curl_easy_setopt( curl, CURLOPT_FTPSSLAUTH, 0 );
curl_easy_setopt( curl, CURLOPT_FTP_SKIP_PASV_IP, 0 );
curl_easy_setopt( curl, CURLOPT_FTPPORT, NULL );
curl_easy_setopt( curl, CURLOPT_SSLVERSION, 0 );
}
/* set port */
if( args_info.port_given ) {
curl_easy_setopt( curl, CURLOPT_PORT, args_info.port_arg );
}
/* compose HTTP headers */
if( args_info.host_given ) {
snprintf( b2, (size_t)2048, "Host: %s", args_info.host_arg );
header_list = curl_slist_append( header_list, b );
}
curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list );
/* set the error buffer */
curl_easy_setopt( curl, CURLOPT_ERRORBUFFER, errbuf );
/* set timeouts */
{
long timeout;
if( args_info.timeout_given )
timeout = args_info.timeout_arg;
else
timeout = DEFAULT_TIMEOUT;
curl_easy_setopt( curl, CURLOPT_CONNECTTIMEOUT, timeout );
curl_easy_setopt( curl, CURLOPT_TIMEOUT, timeout );
}
/* --cacert: CA certificate file to verify SSL connection against (SSL) */
if( args_info.cacert_given ) {
curl_easy_setopt( curl, CURLOPT_CAINFO, args_info.cacert_arg );
/* per default if we have a CA verify both the peer and the
* hostname in the certificate, can be switched off later */
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 2 );
curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2 );
}
/* --no-verify-peer: choose level of CA chain validation (SSL) */
if( args_info.no_verify_peer_given ) {
curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 1 );
}
/* --no-verify-host: make it an additional option, not as in curl! (SSL) */
if( args_info.no_verify_host_given ) {
curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 0 );
}
/* --cert: client certificate to present to server (SSL) */
if( args_info.cert_given ) {
curl_easy_setopt( curl, CURLOPT_SSLCERT, args_info.cert_arg );
}
/* --key: key of the client certificate (SSL) */
if( args_info.key_given ) {
curl_easy_setopt( curl, CURLOPT_SSLKEY, args_info.key_arg );
}
/* do the request */
res = curl_easy_perform( curl );
/* terminate buffer, print it if verbose */
if( args_info.verbose_given ) {
puts( "--- HEADER ---" );
puts( header_buf.buf );
}
if( args_info.verbose_given ) {
puts( "--- BODY ---" );
puts( body_buf.buf );
}
/* free header list, we don't need it anymore */
curl_slist_free_all( header_list );
/* set answer protocol */
if( strcmp( protocol, "http" ) == 0 ) {
answer_protocol = "HTTP";
} else if( strcmp( protocol, "ftp" ) == 0 ) {
answer_protocol = "FTP";
}
/* Curl errors, result in critical Nagios state */
if( res != CURLE_OK ) {
remove_newlines( errbuf );
printf( "%s CRITICAL - %s (error: %d)\n", answer_protocol, errbuf, res );
curl_easy_cleanup( curl );
curl_global_cleanup( );
curlhelp_freebuffer( &body_buf );
curlhelp_freebuffer( &header_buf );
exit( STATE_CRITICAL );
}
/* we got the data and we executed the request in a given time, so we can append
* performance data to the answer always
*/
curl_easy_getinfo( curl, CURLINFO_TOTAL_TIME, &total_time );
snprintf( perfstring, (size_t)1024, "time=%.6gs;%.6g;%.6g;%.6g size=%dB;;;0",
total_time,
args_info.warning_given ? args_info.warning_arg : 0.0,
args_info.critical_given ? args_info.critical_arg : 0.0,
0.0,
(int)body_buf.buflen );
/* -s: check if the excepted string matches */
if( args_info.string_given ) {
if( strstr( body_buf.buf, args_info.string_arg ) == NULL ) {
printf( "HTTP CRITICAL - string not found|%s\n", perfstring );
curl_easy_cleanup( curl );
curl_global_cleanup( );
curlhelp_freebuffer( &body_buf );
curlhelp_freebuffer( &header_buf );
exit( STATE_CRITICAL );
}
}
/* -w, -c: check warning and critical level */
if( args_info.critical_given && ( total_time > args_info.critical_arg ) ) {
level_str = "CRITICAL";
exit_state = STATE_CRITICAL;
}
if( !( exit_state == STATE_CRITICAL ) && args_info.warning_given && ( total_time > args_info.warning_arg ) ) {
level_str = "WARNING";
exit_state = STATE_WARNING;
}
if( strcmp( protocol, "http" ) == 0 ) {
/* get status line of answer, check sanity of HTTP code */
if( curlhelp_parse_statusline( header_buf.buf, &status_line ) < 0 ) {
printf( "HTTP CRITICAL HTTP/1.x %ld unknown - Unparseable status line in %.3g seconds response time|%s\n",
code, total_time, perfstring );
curl_easy_cleanup( curl );
curl_global_cleanup( );
curlhelp_freebuffer( &body_buf );
curlhelp_freebuffer( &header_buf );
exit( STATE_CRITICAL );
}
curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &code );
if( status_line.http_code != code ) {
printf( "HTTP CRITICAL HTTP/%d.%d %d %s - different HTTP codes (cUrl has %ld) in %.3g seconds response time|%s\n",
status_line.http_major, status_line.http_minor,
status_line.http_code, status_line.msg, code,
total_time, perfstring );
curl_easy_cleanup( curl );
curl_global_cleanup( );
curlhelp_free_statusline( &status_line );
curlhelp_freebuffer( &body_buf );
curlhelp_freebuffer( &header_buf );
exit( STATE_CRITICAL );
}
/* check status codes, set exit status accordingly */
if( code >= 600 || code <= 100 ) {
printf( "HTTP CRITICAL HTTP/%d.%d %d %s - Illegal status code (status line: %.40s)\n",
status_line.http_major, status_line.http_minor,
status_line.http_code, status_line.msg,
status_line.first_line );
curl_easy_cleanup( curl );
curl_global_cleanup( );
curlhelp_free_statusline( &status_line );
curlhelp_freebuffer( &body_buf );
curlhelp_freebuffer( &header_buf );
exit( STATE_CRITICAL );
}
if( code >= 500 ) {
level_str = "CRITICAL";
exit_state = STATE_CRITICAL;
} else if( code >= 400 ) {
level_str = "WARNING";
exit_state = STATE_WARNING;
}
printf( "HTTP %s HTTP/%d.%d %d %s - %.3g seconds response time|%s\n",
level_str, status_line.http_major, status_line.http_minor,
status_line.http_code, status_line.msg,
total_time, perfstring );
curlhelp_free_statusline( &status_line );
}
curl_easy_cleanup( curl );
curl_global_cleanup( );
curlhelp_freebuffer( &body_buf );
curlhelp_freebuffer( &header_buf );
exit( exit_state );
}