2013-11-26 22:55:28 +00:00
/*****************************************************************************
2013-11-26 22:59:47 +00:00
*
2014-07-11 19:01:00 +00:00
* Monitoring check_http plugin
2013-11-26 22:59:47 +00:00
*
2013-11-26 22:53:19 +00:00
* License : GPL
2014-07-11 19:01:00 +00:00
* Copyright ( c ) 1999 - 2013 Monitoring Plugins Development Team
2013-11-26 22:59:47 +00:00
*
2013-11-26 22:53:19 +00:00
* Description :
2013-11-26 22:59:47 +00:00
*
2013-11-26 22:53:19 +00:00
* This file contains the check_http plugin
2013-11-26 22:59:47 +00:00
*
2013-11-26 22:55:28 +00:00
* This plugin tests the HTTP service on the specified host . It can test
* normal ( http ) and secure ( https ) servers , follow redirects , search for
* strings and regular expressions , check connection times , and report on
* certificate expiration times .
2013-11-26 22:59:47 +00:00
*
*
2013-11-26 22:55:28 +00:00
* This program is free software : you can redistribute it and / or modify
2013-11-26 22:53:19 +00:00
* it under the terms of the GNU General Public License as published by
2013-11-26 22:55:28 +00:00
* the Free Software Foundation , either version 3 of the License , or
2013-11-26 22:53:19 +00:00
* ( at your option ) any later version .
2013-11-26 22:59:47 +00:00
*
2013-11-26 22:53:19 +00:00
* 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 .
2013-11-26 22:59:47 +00:00
*
2013-11-26 22:53:19 +00:00
* You should have received a copy of the GNU General Public License
2013-11-26 22:55:28 +00:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2013-11-26 22:59:47 +00:00
*
*
2013-11-26 22:55:28 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-11-26 22:53:19 +00:00
/* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
const char * progname = " check_http " ;
2013-11-26 22:59:47 +00:00
const char * copyright = " 1999-2013 " ;
2014-07-11 19:01:00 +00:00
const char * email = " devel@monitoring-plugins.org " ;
2013-11-26 22:53:19 +00:00
# include "common.h"
# include "netutils.h"
# include "utils.h"
2013-11-26 22:54:57 +00:00
# include "base64.h"
2013-11-26 22:55:28 +00:00
# include <ctype.h>
2013-11-26 22:53:19 +00:00
2013-11-26 22:56:50 +00:00
# define STICKY_NONE 0
# define STICKY_HOST 1
# define STICKY_PORT 2
2013-11-26 22:53:19 +00:00
# define HTTP_EXPECT "HTTP / 1."
enum {
MAX_IPV4_HOSTLENGTH = 255 ,
HTTP_PORT = 80 ,
2013-11-26 22:54:42 +00:00
HTTPS_PORT = 443 ,
MAX_PORT = 65535
2013-11-26 22:53:19 +00:00
} ;
# ifdef HAVE_SSL
int check_cert = FALSE ;
2014-07-11 19:01:00 +00:00
int ssl_version = 0 ;
2013-11-26 22:59:06 +00:00
int days_till_exp_warn , days_till_exp_crit ;
2013-11-26 22:53:19 +00:00
char * randbuff ;
X509 * server_cert ;
# define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
# define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
# else /* ifndef HAVE_SSL */
# define my_recv(buf, len) read(sd, buf, len)
# define my_send(buf, len) send(sd, buf, len, 0)
# endif /* HAVE_SSL */
int no_body = FALSE ;
int maximum_age = - 1 ;
enum {
REGS = 2 ,
MAX_RE_SIZE = 256
} ;
# include "regex.h"
regex_t preg ;
regmatch_t pmatch [ REGS ] ;
char regexp [ MAX_RE_SIZE ] ;
char errbuf [ MAX_INPUT_BUFFER ] ;
int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE ;
int errcode ;
int invert_regex = 0 ;
struct timeval tv ;
2013-11-26 22:59:47 +00:00
struct timeval tv_temp ;
2013-11-26 22:53:19 +00:00
# define HTTP_URL " / "
# define CRLF "\r\n"
int specify_port = FALSE ;
int server_port = HTTP_PORT ;
2016-11-30 11:36:55 +00:00
int virtual_port = 0 ;
2013-11-26 22:53:19 +00:00
char server_port_text [ 6 ] = " " ;
char server_type [ 6 ] = " http " ;
char * server_address ;
char * host_name ;
2016-11-30 11:36:55 +00:00
int host_name_length ;
2013-11-26 22:53:19 +00:00
char * server_url ;
char * user_agent ;
int server_url_length ;
int server_expect_yn = 0 ;
char server_expect [ MAX_INPUT_BUFFER ] = HTTP_EXPECT ;
2013-11-26 22:59:47 +00:00
char header_expect [ MAX_INPUT_BUFFER ] = " " ;
2013-11-26 22:53:19 +00:00
char string_expect [ MAX_INPUT_BUFFER ] = " " ;
2013-11-26 22:59:47 +00:00
char output_header_search [ 30 ] = " " ;
2013-11-26 22:57:29 +00:00
char output_string_search [ 30 ] = " " ;
2013-11-26 22:58:53 +00:00
char * warning_thresholds = NULL ;
char * critical_thresholds = NULL ;
thresholds * thlds ;
2013-11-26 22:53:19 +00:00
char user_auth [ MAX_INPUT_BUFFER ] = " " ;
2013-11-26 22:57:29 +00:00
char proxy_auth [ MAX_INPUT_BUFFER ] = " " ;
2013-11-26 22:53:19 +00:00
int display_html = FALSE ;
char * * http_opt_headers ;
int http_opt_headers_count = 0 ;
int onredirect = STATE_OK ;
2013-11-26 22:56:50 +00:00
int followsticky = STICKY_NONE ;
2013-11-26 22:53:19 +00:00
int use_ssl = FALSE ;
2013-11-26 22:57:29 +00:00
int use_sni = FALSE ;
2013-11-26 22:53:19 +00:00
int verbose = FALSE ;
2013-11-26 22:59:47 +00:00
int show_extended_perfdata = FALSE ;
2020-12-10 20:00:09 +00:00
int show_body = FALSE ;
2013-11-26 22:53:19 +00:00
int sd ;
int min_page_len = 0 ;
int max_page_len = 0 ;
int redir_depth = 0 ;
int max_depth = 15 ;
char * http_method ;
2020-12-10 20:00:09 +00:00
char * http_method_proxy ;
2013-11-26 22:53:19 +00:00
char * http_post_data ;
char * http_content_type ;
char buffer [ MAX_INPUT_BUFFER ] ;
2013-11-26 22:59:47 +00:00
char * client_cert = NULL ;
char * client_privkey = NULL ;
2013-11-26 22:53:19 +00:00
int process_arguments ( int , char * * ) ;
int check_http ( void ) ;
void redir ( char * pos , char * status_line ) ;
int server_type_check ( const char * type ) ;
int server_port_check ( int ssl_flag ) ;
char * perfd_time ( double microsec ) ;
2013-11-26 22:59:47 +00:00
char * perfd_time_connect ( double microsec ) ;
char * perfd_time_ssl ( double microsec ) ;
char * perfd_time_firstbyte ( double microsec ) ;
char * perfd_time_headers ( double microsec ) ;
char * perfd_time_transfer ( double microsec ) ;
2013-11-26 22:53:19 +00:00
char * perfd_size ( int page_len ) ;
void print_help ( void ) ;
void print_usage ( void ) ;
int
main ( int argc , char * * argv )
{
int result = STATE_UNKNOWN ;
2013-11-26 22:56:50 +00:00
setlocale ( LC_ALL , " " ) ;
bindtextdomain ( PACKAGE , LOCALEDIR ) ;
textdomain ( PACKAGE ) ;
2013-11-26 22:54:57 +00:00
2013-11-26 22:53:19 +00:00
/* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
server_url = strdup ( HTTP_URL ) ;
server_url_length = strlen ( server_url ) ;
2014-07-11 19:01:00 +00:00
xasprintf ( & user_agent , " User-Agent: check_http/v%s (monitoring-plugins %s) " ,
2013-11-26 22:56:50 +00:00
NP_VERSION , VERSION ) ;
2013-11-26 22:53:19 +00:00
2013-11-26 22:56:50 +00:00
/* Parse extra opts if any */
argv = np_extra_opts ( & argc , argv , progname ) ;
2013-11-26 22:55:28 +00:00
2013-11-26 22:53:19 +00:00
if ( process_arguments ( argc , argv ) = = ERROR )
usage4 ( _ ( " Could not parse arguments " ) ) ;
if ( display_html = = TRUE )
2013-11-26 22:56:50 +00:00
printf ( " <A HREF= \" %s://%s:%d%s \" target= \" _blank \" > " ,
2013-11-26 22:54:57 +00:00
use_ssl ? " https " : " http " , host_name ? host_name : server_address ,
2013-11-26 22:53:19 +00:00
server_port , server_url ) ;
/* initialize alarm signal handling, set socket timeout, start timer */
( void ) signal ( SIGALRM , socket_timeout_alarm_handler ) ;
( void ) alarm ( socket_timeout ) ;
gettimeofday ( & tv , NULL ) ;
result = check_http ( ) ;
return result ;
}
2013-11-26 22:59:47 +00:00
/* check whether a file exists */
void
test_file ( char * path )
{
if ( access ( path , R_OK ) = = 0 )
return ;
usage2 ( _ ( " file does not exist or is not readable " ) , path ) ;
}
2013-11-26 22:53:19 +00:00
/* process command-line arguments */
int
process_arguments ( int argc , char * * argv )
{
int c = 1 ;
2013-11-26 22:55:28 +00:00
char * p ;
2013-11-26 22:59:06 +00:00
char * temp ;
2013-11-26 22:53:19 +00:00
enum {
2013-11-26 22:57:29 +00:00
INVERT_REGEX = CHAR_MAX + 1 ,
SNI_OPTION
2013-11-26 22:53:19 +00:00
} ;
int option = 0 ;
static struct option longopts [ ] = {
STD_LONG_OPTS ,
{ " link " , no_argument , 0 , ' L ' } ,
{ " nohtml " , no_argument , 0 , ' n ' } ,
2013-11-26 22:58:53 +00:00
{ " ssl " , optional_argument , 0 , ' S ' } ,
2013-11-26 22:57:29 +00:00
{ " sni " , no_argument , 0 , SNI_OPTION } ,
2013-11-26 22:53:19 +00:00
{ " post " , required_argument , 0 , ' P ' } ,
2013-11-26 22:56:50 +00:00
{ " method " , required_argument , 0 , ' j ' } ,
2013-11-26 22:53:19 +00:00
{ " IP-address " , required_argument , 0 , ' I ' } ,
{ " url " , required_argument , 0 , ' u ' } ,
2013-11-26 22:53:44 +00:00
{ " port " , required_argument , 0 , ' p ' } ,
{ " authorization " , required_argument , 0 , ' a ' } ,
2013-11-26 23:00:26 +00:00
{ " proxy-authorization " , required_argument , 0 , ' b ' } ,
2013-11-26 22:59:47 +00:00
{ " header-string " , required_argument , 0 , ' d ' } ,
2013-11-26 22:53:19 +00:00
{ " string " , required_argument , 0 , ' s ' } ,
2013-11-26 22:53:44 +00:00
{ " expect " , required_argument , 0 , ' e ' } ,
2013-11-26 22:53:19 +00:00
{ " regex " , required_argument , 0 , ' r ' } ,
{ " ereg " , required_argument , 0 , ' r ' } ,
{ " eregi " , required_argument , 0 , ' R ' } ,
{ " linespan " , no_argument , 0 , ' l ' } ,
{ " onredirect " , required_argument , 0 , ' f ' } ,
{ " certificate " , required_argument , 0 , ' C ' } ,
2013-11-26 22:59:47 +00:00
{ " client-cert " , required_argument , 0 , ' J ' } ,
{ " private-key " , required_argument , 0 , ' K ' } ,
2013-11-26 22:53:19 +00:00
{ " useragent " , required_argument , 0 , ' A ' } ,
{ " header " , required_argument , 0 , ' k ' } ,
{ " no-body " , no_argument , 0 , ' N ' } ,
{ " max-age " , required_argument , 0 , ' M ' } ,
{ " content-type " , required_argument , 0 , ' T ' } ,
{ " pagesize " , required_argument , 0 , ' m ' } ,
{ " invert-regex " , no_argument , NULL , INVERT_REGEX } ,
{ " use-ipv4 " , no_argument , 0 , ' 4 ' } ,
{ " use-ipv6 " , no_argument , 0 , ' 6 ' } ,
2013-11-26 22:59:47 +00:00
{ " extended-perfdata " , no_argument , 0 , ' E ' } ,
2020-12-10 20:00:09 +00:00
{ " show-body " , no_argument , 0 , ' B ' } ,
2013-11-26 22:53:19 +00:00
{ 0 , 0 , 0 , 0 }
} ;
if ( argc < 2 )
return ERROR ;
for ( c = 1 ; c < argc ; c + + ) {
if ( strcmp ( " -to " , argv [ c ] ) = = 0 )
strcpy ( argv [ c ] , " -t " ) ;
if ( strcmp ( " -hn " , argv [ c ] ) = = 0 )
strcpy ( argv [ c ] , " -H " ) ;
if ( strcmp ( " -wt " , argv [ c ] ) = = 0 )
strcpy ( argv [ c ] , " -w " ) ;
if ( strcmp ( " -ct " , argv [ c ] ) = = 0 )
strcpy ( argv [ c ] , " -c " ) ;
if ( strcmp ( " -nohtml " , argv [ c ] ) = = 0 )
strcpy ( argv [ c ] , " -n " ) ;
}
while ( 1 ) {
2020-12-10 20:00:09 +00:00
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:nlLS::m:M:NEB " , longopts , & option ) ;
2013-11-26 22:53:19 +00:00
if ( c = = - 1 | | c = = EOF )
break ;
switch ( c ) {
case ' ? ' : /* usage */
2013-11-26 22:53:44 +00:00
usage5 ( ) ;
2013-11-26 22:53:19 +00:00
break ;
case ' h ' : /* help */
print_help ( ) ;
2016-11-30 11:36:55 +00:00
exit ( STATE_UNKNOWN ) ;
2013-11-26 22:53:19 +00:00
break ;
case ' V ' : /* version */
2013-11-26 22:56:50 +00:00
print_revision ( progname , NP_VERSION ) ;
2016-11-30 11:36:55 +00:00
exit ( STATE_UNKNOWN ) ;
2013-11-26 22:53:19 +00:00
break ;
case ' t ' : /* timeout period */
if ( ! is_intnonneg ( optarg ) )
usage2 ( _ ( " Timeout interval must be a positive integer " ) , optarg ) ;
else
socket_timeout = atoi ( optarg ) ;
break ;
case ' c ' : /* critical time threshold */
2013-11-26 22:58:53 +00:00
critical_thresholds = optarg ;
2013-11-26 22:53:19 +00:00
break ;
case ' w ' : /* warning time threshold */
2013-11-26 22:58:53 +00:00
warning_thresholds = optarg ;
2013-11-26 22:53:19 +00:00
break ;
case ' A ' : /* User Agent String */
2013-11-26 22:59:47 +00:00
xasprintf ( & user_agent , " User-Agent: %s " , optarg ) ;
2013-11-26 22:53:19 +00:00
break ;
case ' k ' : /* Additional headers */
if ( http_opt_headers_count = = 0 )
http_opt_headers = malloc ( sizeof ( char * ) * ( + + http_opt_headers_count ) ) ;
else
http_opt_headers = realloc ( http_opt_headers , sizeof ( char * ) * ( + + http_opt_headers_count ) ) ;
http_opt_headers [ http_opt_headers_count - 1 ] = optarg ;
2013-11-26 22:59:47 +00:00
/* xasprintf (&http_opt_headers, "%s", optarg); */
2013-11-26 22:53:19 +00:00
break ;
case ' L ' : /* show html link */
display_html = TRUE ;
break ;
case ' n ' : /* do not show html link */
display_html = FALSE ;
break ;
case ' C ' : /* Check SSL cert validity */
# ifdef HAVE_SSL
2013-11-26 22:59:06 +00:00
if ( ( temp = strchr ( optarg , ' , ' ) ) ! = NULL ) {
2013-11-26 22:59:47 +00:00
* temp = ' \0 ' ;
if ( ! is_intnonneg ( optarg ) )
usage2 ( _ ( " Invalid certificate expiration period " ) , optarg ) ;
days_till_exp_warn = atoi ( optarg ) ;
* temp = ' , ' ;
temp + + ;
if ( ! is_intnonneg ( temp ) )
usage2 ( _ ( " Invalid certificate expiration period " ) , temp ) ;
days_till_exp_crit = atoi ( temp ) ;
2013-11-26 22:59:06 +00:00
}
2013-11-26 22:53:19 +00:00
else {
2013-11-26 22:59:47 +00:00
days_till_exp_crit = 0 ;
2013-11-26 22:59:06 +00:00
if ( ! is_intnonneg ( optarg ) )
usage2 ( _ ( " Invalid certificate expiration period " ) , optarg ) ;
days_till_exp_warn = atoi ( optarg ) ;
2013-11-26 22:53:19 +00:00
}
2013-11-26 22:59:06 +00:00
check_cert = TRUE ;
2013-11-26 22:59:47 +00:00
goto enable_ssl ;
2013-11-26 22:53:19 +00:00
# endif
2013-11-26 22:59:47 +00:00
case ' J ' : /* use client certificate */
# ifdef HAVE_SSL
test_file ( optarg ) ;
client_cert = optarg ;
goto enable_ssl ;
# endif
case ' K ' : /* use client private key */
# ifdef HAVE_SSL
test_file ( optarg ) ;
client_privkey = optarg ;
goto enable_ssl ;
2013-11-26 22:53:19 +00:00
# endif
2013-11-26 22:59:47 +00:00
case ' S ' : /* use SSL */
# ifdef HAVE_SSL
enable_ssl :
2014-07-11 19:01:00 +00:00
/* ssl_version initialized to 0 as a default. Only set if it's non-zero. This helps when we include multiple
parameters , like - S and - C combinations */
2013-11-26 22:53:19 +00:00
use_ssl = TRUE ;
2014-07-11 19:01:00 +00:00
if ( c = = ' S ' & & optarg ! = NULL ) {
2016-11-30 11:36:55 +00:00
int got_plus = strchr ( optarg , ' + ' ) ! = NULL ;
if ( ! strncmp ( optarg , " 1.2 " , 3 ) )
ssl_version = got_plus ? MP_TLSv1_2_OR_NEWER : MP_TLSv1_2 ;
else if ( ! strncmp ( optarg , " 1.1 " , 3 ) )
ssl_version = got_plus ? MP_TLSv1_1_OR_NEWER : MP_TLSv1_1 ;
else if ( optarg [ 0 ] = = ' 1 ' )
ssl_version = got_plus ? MP_TLSv1_OR_NEWER : MP_TLSv1 ;
else if ( optarg [ 0 ] = = ' 3 ' )
ssl_version = got_plus ? MP_SSLv3_OR_NEWER : MP_SSLv3 ;
else if ( optarg [ 0 ] = = ' 2 ' )
ssl_version = got_plus ? MP_SSLv2_OR_NEWER : MP_SSLv2 ;
else
usage4 ( _ ( " Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with optional '+' suffix) " ) ) ;
2013-11-26 22:58:53 +00:00
}
2013-11-26 22:53:19 +00:00
if ( specify_port = = FALSE )
server_port = HTTPS_PORT ;
2013-11-26 22:59:47 +00:00
# else
/* -C -J and -K fall through to here without SSL */
usage4 ( _ ( " Invalid option - SSL is not available " ) ) ;
# endif
2013-11-26 22:53:19 +00:00
break ;
2013-11-26 22:57:29 +00:00
case SNI_OPTION :
use_sni = TRUE ;
break ;
2013-11-26 22:53:19 +00:00
case ' f ' : /* onredirect */
2013-11-26 22:56:50 +00:00
if ( ! strcmp ( optarg , " stickyport " ) )
onredirect = STATE_DEPENDENT , followsticky = STICKY_HOST | STICKY_PORT ;
else if ( ! strcmp ( optarg , " sticky " ) )
onredirect = STATE_DEPENDENT , followsticky = STICKY_HOST ;
else if ( ! strcmp ( optarg , " follow " ) )
onredirect = STATE_DEPENDENT , followsticky = STICKY_NONE ;
else if ( ! strcmp ( optarg , " unknown " ) )
2013-11-26 22:53:19 +00:00
onredirect = STATE_UNKNOWN ;
2013-11-26 22:56:50 +00:00
else if ( ! strcmp ( optarg , " ok " ) )
2013-11-26 22:53:19 +00:00
onredirect = STATE_OK ;
2013-11-26 22:56:50 +00:00
else if ( ! strcmp ( optarg , " warning " ) )
2013-11-26 22:53:19 +00:00
onredirect = STATE_WARNING ;
2013-11-26 22:56:50 +00:00
else if ( ! strcmp ( optarg , " critical " ) )
2013-11-26 22:53:19 +00:00
onredirect = STATE_CRITICAL ;
2013-11-26 22:56:50 +00:00
else usage2 ( _ ( " Invalid onredirect option " ) , optarg ) ;
2013-11-26 22:53:19 +00:00
if ( verbose )
2013-11-26 22:56:50 +00:00
printf ( _ ( " option f:%d \n " ) , onredirect ) ;
2013-11-26 22:53:19 +00:00
break ;
/* Note: H, I, and u must be malloc'd or will fail on redirects */
case ' H ' : /* Host Name (virtual host) */
host_name = strdup ( optarg ) ;
2013-11-26 22:55:28 +00:00
if ( host_name [ 0 ] = = ' [ ' ) {
2016-11-30 11:36:55 +00:00
if ( ( p = strstr ( host_name , " ]: " ) ) ! = NULL ) { /* [IPv6]:port */
virtual_port = atoi ( p + 2 ) ;
/* cut off the port */
host_name_length = strlen ( host_name ) - strlen ( p ) - 1 ;
free ( host_name ) ;
host_name = strndup ( optarg , host_name_length ) ;
if ( specify_port = = FALSE )
server_port = virtual_port ;
}
2013-11-26 22:55:28 +00:00
} else if ( ( p = strchr ( host_name , ' : ' ) ) ! = NULL
2016-11-30 11:36:55 +00:00
& & strchr ( + + p , ' : ' ) = = NULL ) { /* IPv4:port or host:port */
virtual_port = atoi ( p ) ;
/* cut off the port */
host_name_length = strlen ( host_name ) - strlen ( p ) - 1 ;
free ( host_name ) ;
host_name = strndup ( optarg , host_name_length ) ;
if ( specify_port = = FALSE )
server_port = virtual_port ;
}
2013-11-26 22:53:19 +00:00
break ;
case ' I ' : /* Server IP-address */
server_address = strdup ( optarg ) ;
break ;
case ' u ' : /* URL path */
server_url = strdup ( optarg ) ;
server_url_length = strlen ( server_url ) ;
break ;
case ' p ' : /* Server port */
if ( ! is_intnonneg ( optarg ) )
usage2 ( _ ( " Invalid port number " ) , optarg ) ;
else {
server_port = atoi ( optarg ) ;
specify_port = TRUE ;
}
break ;
case ' a ' : /* authorization info */
strncpy ( user_auth , optarg , MAX_INPUT_BUFFER - 1 ) ;
user_auth [ MAX_INPUT_BUFFER - 1 ] = 0 ;
break ;
2013-11-26 22:57:29 +00:00
case ' b ' : /* proxy-authorization info */
strncpy ( proxy_auth , optarg , MAX_INPUT_BUFFER - 1 ) ;
proxy_auth [ MAX_INPUT_BUFFER - 1 ] = 0 ;
break ;
2013-11-26 22:56:50 +00:00
case ' P ' : /* HTTP POST data in URL encoded format; ignored if settings already */
if ( ! http_post_data )
http_post_data = strdup ( optarg ) ;
if ( ! http_method )
http_method = strdup ( " POST " ) ;
break ;
case ' j ' : /* Set HTTP method */
if ( http_method )
free ( http_method ) ;
http_method = strdup ( optarg ) ;
2020-12-10 20:00:09 +00:00
char * tmp ;
if ( ( tmp = strstr ( http_method , " : " ) ) > 0 ) {
tmp [ 0 ] = ' \0 ' ;
http_method = http_method ;
http_method_proxy = + + tmp ;
}
2013-11-26 22:53:19 +00:00
break ;
2013-11-26 22:59:47 +00:00
case ' d ' : /* string or substring */
strncpy ( header_expect , optarg , MAX_INPUT_BUFFER - 1 ) ;
header_expect [ MAX_INPUT_BUFFER - 1 ] = 0 ;
break ;
2013-11-26 22:53:19 +00:00
case ' s ' : /* string or substring */
strncpy ( string_expect , optarg , MAX_INPUT_BUFFER - 1 ) ;
string_expect [ MAX_INPUT_BUFFER - 1 ] = 0 ;
break ;
case ' e ' : /* string or substring */
strncpy ( server_expect , optarg , MAX_INPUT_BUFFER - 1 ) ;
server_expect [ MAX_INPUT_BUFFER - 1 ] = 0 ;
server_expect_yn = 1 ;
break ;
case ' T ' : /* Content-type */
2013-11-26 22:59:47 +00:00
xasprintf ( & http_content_type , " %s " , optarg ) ;
2013-11-26 22:53:19 +00:00
break ;
case ' l ' : /* linespan */
cflags & = ~ REG_NEWLINE ;
break ;
case ' R ' : /* regex */
cflags | = REG_ICASE ;
case ' r ' : /* regex */
strncpy ( regexp , optarg , MAX_RE_SIZE - 1 ) ;
regexp [ MAX_RE_SIZE - 1 ] = 0 ;
errcode = regcomp ( & preg , regexp , cflags ) ;
if ( errcode ! = 0 ) {
( void ) regerror ( errcode , & preg , errbuf , MAX_INPUT_BUFFER ) ;
printf ( _ ( " Could Not Compile Regular Expression: %s " ) , errbuf ) ;
return ERROR ;
}
break ;
case INVERT_REGEX :
invert_regex = 1 ;
break ;
case ' 4 ' :
address_family = AF_INET ;
break ;
case ' 6 ' :
# ifdef USE_IPV6
address_family = AF_INET6 ;
# else
usage4 ( _ ( " IPv6 support not available " ) ) ;
# endif
break ;
case ' v ' : /* verbose */
verbose = TRUE ;
break ;
case ' m ' : /* min_page_length */
{
char * tmp ;
if ( strchr ( optarg , ' : ' ) ! = ( char * ) NULL ) {
/* range, so get two values, min:max */
tmp = strtok ( optarg , " : " ) ;
if ( tmp = = NULL ) {
printf ( " Bad format: try \" -m min:max \" \n " ) ;
exit ( STATE_WARNING ) ;
} else
min_page_len = atoi ( tmp ) ;
tmp = strtok ( NULL , " : " ) ;
if ( tmp = = NULL ) {
printf ( " Bad format: try \" -m min:max \" \n " ) ;
exit ( STATE_WARNING ) ;
} else
max_page_len = atoi ( tmp ) ;
2013-11-26 22:56:50 +00:00
} else
2013-11-26 22:53:19 +00:00
min_page_len = atoi ( optarg ) ;
break ;
}
case ' N ' : /* no-body */
no_body = TRUE ;
break ;
case ' M ' : /* max-age */
{
int L = strlen ( optarg ) ;
if ( L & & optarg [ L - 1 ] = = ' m ' )
maximum_age = atoi ( optarg ) * 60 ;
else if ( L & & optarg [ L - 1 ] = = ' h ' )
maximum_age = atoi ( optarg ) * 60 * 60 ;
else if ( L & & optarg [ L - 1 ] = = ' d ' )
maximum_age = atoi ( optarg ) * 60 * 60 * 24 ;
else if ( L & & ( optarg [ L - 1 ] = = ' s ' | |
isdigit ( optarg [ L - 1 ] ) ) )
maximum_age = atoi ( optarg ) ;
else {
fprintf ( stderr , " unparsable max-age: %s \n " , optarg ) ;
exit ( STATE_WARNING ) ;
}
}
break ;
2013-11-26 22:59:47 +00:00
case ' E ' : /* show extended perfdata */
show_extended_perfdata = TRUE ;
break ;
2020-12-10 20:00:09 +00:00
case ' B ' : /* print body content after status line */
show_body = TRUE ;
break ;
2013-11-26 22:53:19 +00:00
}
}
c = optind ;
if ( server_address = = NULL & & c < argc )
server_address = strdup ( argv [ c + + ] ) ;
if ( host_name = = NULL & & c < argc )
host_name = strdup ( argv [ c + + ] ) ;
if ( server_address = = NULL ) {
if ( host_name = = NULL )
usage4 ( _ ( " You must specify a server address or host name " ) ) ;
else
server_address = strdup ( host_name ) ;
}
2013-11-26 22:58:53 +00:00
set_thresholds ( & thlds , warning_thresholds , critical_thresholds ) ;
if ( critical_thresholds & & thlds - > critical - > end > ( double ) socket_timeout )
socket_timeout = ( int ) thlds - > critical - > end + 1 ;
2013-11-26 22:53:19 +00:00
if ( http_method = = NULL )
http_method = strdup ( " GET " ) ;
2020-12-10 20:00:09 +00:00
if ( http_method_proxy = = NULL )
http_method_proxy = strdup ( " GET " ) ;
2016-11-30 11:36:55 +00:00
if ( client_cert & & ! client_privkey )
2013-11-26 22:59:47 +00:00
usage4 ( _ ( " If you use a client certificate you must also specify a private key file " ) ) ;
2016-11-30 11:36:55 +00:00
if ( virtual_port = = 0 )
virtual_port = server_port ;
2013-11-26 22:53:19 +00:00
return TRUE ;
}
/* Returns 1 if we're done processing the document body; 0 to keep going */
static int
document_headers_done ( char * full_page )
{
const char * body ;
for ( body = full_page ; * body ; body + + ) {
if ( ! strncmp ( body , " \n \n " , 2 ) | | ! strncmp ( body , " \n \r \n " , 3 ) )
break ;
}
if ( ! * body )
return 0 ; /* haven't read end of headers yet */
full_page [ body - full_page ] = 0 ;
return 1 ;
}
static time_t
parse_time_string ( const char * string )
{
struct tm tm ;
time_t t ;
memset ( & tm , 0 , sizeof ( tm ) ) ;
/* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
if ( isupper ( string [ 0 ] ) & & /* Tue */
islower ( string [ 1 ] ) & &
islower ( string [ 2 ] ) & &
' , ' = = string [ 3 ] & &
' ' = = string [ 4 ] & &
( isdigit ( string [ 5 ] ) | | string [ 5 ] = = ' ' ) & & /* 25 */
isdigit ( string [ 6 ] ) & &
' ' = = string [ 7 ] & &
isupper ( string [ 8 ] ) & & /* Dec */
islower ( string [ 9 ] ) & &
islower ( string [ 10 ] ) & &
' ' = = string [ 11 ] & &
isdigit ( string [ 12 ] ) & & /* 2001 */
isdigit ( string [ 13 ] ) & &
isdigit ( string [ 14 ] ) & &
isdigit ( string [ 15 ] ) & &
' ' = = string [ 16 ] & &
isdigit ( string [ 17 ] ) & & /* 02: */
isdigit ( string [ 18 ] ) & &
' : ' = = string [ 19 ] & &
isdigit ( string [ 20 ] ) & & /* 59: */
isdigit ( string [ 21 ] ) & &
' : ' = = string [ 22 ] & &
isdigit ( string [ 23 ] ) & & /* 03 */
isdigit ( string [ 24 ] ) & &
' ' = = string [ 25 ] & &
' G ' = = string [ 26 ] & & /* GMT */
' M ' = = string [ 27 ] & & /* GMT */
' T ' = = string [ 28 ] ) {
tm . tm_sec = 10 * ( string [ 23 ] - ' 0 ' ) + ( string [ 24 ] - ' 0 ' ) ;
tm . tm_min = 10 * ( string [ 20 ] - ' 0 ' ) + ( string [ 21 ] - ' 0 ' ) ;
tm . tm_hour = 10 * ( string [ 17 ] - ' 0 ' ) + ( string [ 18 ] - ' 0 ' ) ;
tm . tm_mday = 10 * ( string [ 5 ] = = ' ' ? 0 : string [ 5 ] - ' 0 ' ) + ( string [ 6 ] - ' 0 ' ) ;
tm . tm_mon = ( ! strncmp ( string + 8 , " Jan " , 3 ) ? 0 :
! strncmp ( string + 8 , " Feb " , 3 ) ? 1 :
! strncmp ( string + 8 , " Mar " , 3 ) ? 2 :
! strncmp ( string + 8 , " Apr " , 3 ) ? 3 :
! strncmp ( string + 8 , " May " , 3 ) ? 4 :
! strncmp ( string + 8 , " Jun " , 3 ) ? 5 :
! strncmp ( string + 8 , " Jul " , 3 ) ? 6 :
! strncmp ( string + 8 , " Aug " , 3 ) ? 7 :
! strncmp ( string + 8 , " Sep " , 3 ) ? 8 :
! strncmp ( string + 8 , " Oct " , 3 ) ? 9 :
! strncmp ( string + 8 , " Nov " , 3 ) ? 10 :
! strncmp ( string + 8 , " Dec " , 3 ) ? 11 :
- 1 ) ;
tm . tm_year = ( ( 1000 * ( string [ 12 ] - ' 0 ' ) +
100 * ( string [ 13 ] - ' 0 ' ) +
10 * ( string [ 14 ] - ' 0 ' ) +
( string [ 15 ] - ' 0 ' ) )
- 1900 ) ;
tm . tm_isdst = 0 ; /* GMT is never in DST, right? */
if ( tm . tm_mon < 0 | | tm . tm_mday < 1 | | tm . tm_mday > 31 )
return 0 ;
2013-11-26 22:56:50 +00:00
/*
2013-11-26 22:53:19 +00:00
This is actually wrong : we need to subtract the local timezone
offset from GMT from this value . But , that ' s ok in this usage ,
because we only comparing these two GMT dates against each other ,
so it doesn ' t matter what time zone we parse them in .
*/
t = mktime ( & tm ) ;
if ( t = = ( time_t ) - 1 ) t = 0 ;
if ( verbose ) {
const char * s = string ;
while ( * s & & * s ! = ' \r ' & & * s ! = ' \n ' )
fputc ( * s + + , stdout ) ;
printf ( " ==> %lu \n " , ( unsigned long ) t ) ;
}
return t ;
} else {
return 0 ;
}
}
2013-11-26 22:56:50 +00:00
/* Checks if the server 'reply' is one of the expected 'statuscodes' */
static int
expected_statuscode ( const char * reply , const char * statuscodes )
{
char * expected , * code ;
int result = 0 ;
if ( ( expected = strdup ( statuscodes ) ) = = NULL )
die ( STATE_UNKNOWN , _ ( " HTTP UNKNOWN - Memory allocation error \n " ) ) ;
for ( code = strtok ( expected , " , " ) ; code ! = NULL ; code = strtok ( NULL , " , " ) )
if ( strstr ( reply , code ) ! = NULL ) {
result = 1 ;
break ;
}
2013-11-26 22:53:19 +00:00
2013-11-26 22:56:50 +00:00
free ( expected ) ;
return result ;
}
2013-11-26 22:53:19 +00:00
2013-11-26 22:56:50 +00:00
static int
check_document_dates ( const char * headers , char * * msg )
2013-11-26 22:53:19 +00:00
{
const char * s ;
char * server_date = 0 ;
char * document_date = 0 ;
2013-11-26 22:56:50 +00:00
int date_result = STATE_OK ;
2013-11-26 22:53:19 +00:00
s = headers ;
while ( * s ) {
const char * field = s ;
const char * value = 0 ;
/* Find the end of the header field */
while ( * s & & ! isspace ( * s ) & & * s ! = ' : ' )
s + + ;
/* Remember the header value, if any. */
if ( * s = = ' : ' )
value = + + s ;
/* Skip to the end of the header, including continuation lines. */
while ( * s & & ! ( * s = = ' \n ' & & ( s [ 1 ] ! = ' ' & & s [ 1 ] ! = ' \t ' ) ) )
s + + ;
2013-11-26 22:56:50 +00:00
/* Avoid stepping over end-of-string marker */
if ( * s )
s + + ;
2013-11-26 22:53:19 +00:00
/* Process this header. */
if ( value & & value > field + 2 ) {
char * ff = ( char * ) malloc ( value - field ) ;
char * ss = ff ;
while ( field < value - 1 )
* ss + + = tolower ( * field + + ) ;
* ss + + = 0 ;
if ( ! strcmp ( ff , " date " ) | | ! strcmp ( ff , " last-modified " ) ) {
const char * e ;
while ( * value & & isspace ( * value ) )
value + + ;
for ( e = value ; * e & & * e ! = ' \r ' & & * e ! = ' \n ' ; e + + )
;
ss = ( char * ) malloc ( e - value + 1 ) ;
strncpy ( ss , value , e - value ) ;
ss [ e - value ] = 0 ;
if ( ! strcmp ( ff , " date " ) ) {
if ( server_date ) free ( server_date ) ;
server_date = ss ;
} else {
if ( document_date ) free ( document_date ) ;
document_date = ss ;
}
}
free ( ff ) ;
}
}
/* Done parsing the body. Now check the dates we (hopefully) parsed. */
if ( ! server_date | | ! * server_date ) {
2013-11-26 22:59:47 +00:00
xasprintf ( msg , _ ( " %sServer date unknown, " ) , * msg ) ;
2013-11-26 22:56:50 +00:00
date_result = max_state_alt ( STATE_UNKNOWN , date_result ) ;
2013-11-26 22:53:19 +00:00
} else if ( ! document_date | | ! * document_date ) {
2013-11-26 22:59:47 +00:00
xasprintf ( msg , _ ( " %sDocument modification date unknown, " ) , * msg ) ;
2013-11-26 22:56:50 +00:00
date_result = max_state_alt ( STATE_CRITICAL , date_result ) ;
2013-11-26 22:53:19 +00:00
} else {
time_t srv_data = parse_time_string ( server_date ) ;
time_t doc_data = parse_time_string ( document_date ) ;
if ( srv_data < = 0 ) {
2013-11-26 22:59:47 +00:00
xasprintf ( msg , _ ( " %sServer date \" %100s \" unparsable, " ) , * msg , server_date ) ;
2013-11-26 22:56:50 +00:00
date_result = max_state_alt ( STATE_CRITICAL , date_result ) ;
2013-11-26 22:53:19 +00:00
} else if ( doc_data < = 0 ) {
2013-11-26 22:59:47 +00:00
xasprintf ( msg , _ ( " %sDocument date \" %100s \" unparsable, " ) , * msg , document_date ) ;
2013-11-26 22:56:50 +00:00
date_result = max_state_alt ( STATE_CRITICAL , date_result ) ;
2013-11-26 22:53:19 +00:00
} else if ( doc_data > srv_data + 30 ) {
2013-11-26 22:59:47 +00:00
xasprintf ( msg , _ ( " %sDocument is %d seconds in the future, " ) , * msg , ( int ) doc_data - ( int ) srv_data ) ;
2013-11-26 22:56:50 +00:00
date_result = max_state_alt ( STATE_CRITICAL , date_result ) ;
2013-11-26 22:53:19 +00:00
} else if ( doc_data < srv_data - maximum_age ) {
2013-11-26 22:56:50 +00:00
int n = ( srv_data - doc_data ) ;
if ( n > ( 60 * 60 * 24 * 2 ) ) {
2013-11-26 22:59:47 +00:00
xasprintf ( msg , _ ( " %sLast modified %.1f days ago, " ) , * msg , ( ( float ) n ) / ( 60 * 60 * 24 ) ) ;
2013-11-26 22:56:50 +00:00
date_result = max_state_alt ( STATE_CRITICAL , date_result ) ;
} else {
2013-11-26 22:59:47 +00:00
xasprintf ( msg , _ ( " %sLast modified %d:%02d:%02d ago, " ) , * msg , n / ( 60 * 60 ) , ( n / 60 ) % 60 , n % 60 ) ;
2013-11-26 22:56:50 +00:00
date_result = max_state_alt ( STATE_CRITICAL , date_result ) ;
}
2013-11-26 22:53:19 +00:00
}
free ( server_date ) ;
free ( document_date ) ;
}
2013-11-26 22:56:50 +00:00
return date_result ;
2013-11-26 22:53:19 +00:00
}
int
get_content_length ( const char * headers )
{
const char * s ;
int content_length = 0 ;
s = headers ;
while ( * s ) {
const char * field = s ;
const char * value = 0 ;
/* Find the end of the header field */
while ( * s & & ! isspace ( * s ) & & * s ! = ' : ' )
s + + ;
/* Remember the header value, if any. */
if ( * s = = ' : ' )
value = + + s ;
/* Skip to the end of the header, including continuation lines. */
while ( * s & & ! ( * s = = ' \n ' & & ( s [ 1 ] ! = ' ' & & s [ 1 ] ! = ' \t ' ) ) )
s + + ;
2013-11-26 22:57:29 +00:00
/* Avoid stepping over end-of-string marker */
if ( * s )
s + + ;
2013-11-26 22:53:19 +00:00
/* Process this header. */
if ( value & & value > field + 2 ) {
char * ff = ( char * ) malloc ( value - field ) ;
char * ss = ff ;
while ( field < value - 1 )
* ss + + = tolower ( * field + + ) ;
* ss + + = 0 ;
if ( ! strcmp ( ff , " content-length " ) ) {
const char * e ;
while ( * value & & isspace ( * value ) )
value + + ;
for ( e = value ; * e & & * e ! = ' \r ' & & * e ! = ' \n ' ; e + + )
;
ss = ( char * ) malloc ( e - value + 1 ) ;
strncpy ( ss , value , e - value ) ;
ss [ e - value ] = 0 ;
content_length = atoi ( ss ) ;
free ( ss ) ;
}
free ( ff ) ;
}
}
return ( content_length ) ;
}
2013-11-26 22:56:50 +00:00
char *
prepend_slash ( char * path )
{
char * newpath ;
if ( path [ 0 ] = = ' / ' )
return path ;
if ( ( newpath = malloc ( strlen ( path ) + 2 ) ) = = NULL )
die ( STATE_UNKNOWN , _ ( " HTTP UNKNOWN - Memory allocation error \n " ) ) ;
newpath [ 0 ] = ' / ' ;
strcpy ( newpath + 1 , path ) ;
free ( path ) ;
return newpath ;
}
2013-11-26 22:53:19 +00:00
int
check_http ( void )
{
char * msg ;
char * status_line ;
char * status_code ;
char * header ;
char * page ;
char * auth ;
int http_status ;
int i = 0 ;
size_t pagesize = 0 ;
char * full_page ;
2013-11-26 22:57:29 +00:00
char * full_page_new ;
2013-11-26 22:53:19 +00:00
char * buf ;
char * pos ;
2013-11-26 23:00:34 +00:00
long microsec = 0L ;
double elapsed_time = 0.0 ;
long microsec_connect = 0L ;
double elapsed_time_connect = 0.0 ;
long microsec_ssl = 0L ;
double elapsed_time_ssl = 0.0 ;
long microsec_firstbyte = 0L ;
double elapsed_time_firstbyte = 0.0 ;
long microsec_headers = 0L ;
double elapsed_time_headers = 0.0 ;
long microsec_transfer = 0L ;
double elapsed_time_transfer = 0.0 ;
2013-11-26 22:53:19 +00:00
int page_len = 0 ;
2013-11-26 22:56:50 +00:00
int result = STATE_OK ;
2016-11-30 11:36:55 +00:00
char * force_host_header = NULL ;
2013-11-26 22:53:19 +00:00
/* try to connect to the host at the given port number */
2013-11-26 22:59:47 +00:00
gettimeofday ( & tv_temp , NULL ) ;
2013-11-26 22:53:19 +00:00
if ( my_tcp_connect ( server_address , server_port , & sd ) ! = STATE_OK )
2013-11-26 22:54:42 +00:00
die ( STATE_CRITICAL , _ ( " HTTP CRITICAL - Unable to open TCP socket \n " ) ) ;
2013-11-26 22:59:47 +00:00
microsec_connect = deltime ( tv_temp ) ;
2016-11-30 11:36:55 +00:00
/* if we are called with the -I option, the -j method is CONNECT and */
/* we received -S for SSL, then we tunnel the request through a proxy*/
/* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */
if ( server_address ! = NULL & & strcmp ( http_method , " CONNECT " ) = = 0
& & host_name ! = NULL & & use_ssl = = TRUE ) {
if ( verbose ) printf ( " Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d \n " , server_address , server_port , host_name , HTTPS_PORT ) ;
asprintf ( & buf , " %s %s:%d HTTP/1.1 \r \n %s \r \n " , http_method , host_name , HTTPS_PORT , user_agent ) ;
2020-12-10 20:00:09 +00:00
if ( strlen ( proxy_auth ) ) {
base64_encode_alloc ( proxy_auth , strlen ( proxy_auth ) , & auth ) ;
xasprintf ( & buf , " %sProxy-Authorization: Basic %s \r \n " , buf , auth ) ;
}
/* optionally send any other header tag */
if ( http_opt_headers_count ) {
for ( i = 0 ; i < http_opt_headers_count ; i + + ) {
if ( force_host_header ! = http_opt_headers [ i ] ) {
xasprintf ( & buf , " %s%s \r \n " , buf , http_opt_headers [ i ] ) ;
}
}
/* This cannot be free'd here because a redirection will then try to access this and segfault */
/* Covered in a testcase in tests/check_http.t */
/* free(http_opt_headers); */
}
2016-11-30 11:36:55 +00:00
asprintf ( & buf , " %sProxy-Connection: keep-alive \r \n " , buf ) ;
asprintf ( & buf , " %sHost: %s \r \n " , buf , host_name ) ;
/* we finished our request, send empty line with CRLF */
asprintf ( & buf , " %s%s " , buf , CRLF ) ;
if ( verbose ) printf ( " %s \n " , buf ) ;
send ( sd , buf , strlen ( buf ) , 0 ) ;
buf [ 0 ] = ' \0 ' ;
if ( verbose ) printf ( " Receive response from proxy \n " ) ;
read ( sd , buffer , MAX_INPUT_BUFFER - 1 ) ;
if ( verbose ) printf ( " %s " , buffer ) ;
/* Here we should check if we got HTTP/1.1 200 Connection established */
}
2013-11-26 22:53:19 +00:00
# ifdef HAVE_SSL
2013-11-26 22:59:47 +00:00
elapsed_time_connect = ( double ) microsec_connect / 1.0e6 ;
2013-11-26 22:53:19 +00:00
if ( use_ssl = = TRUE ) {
2013-11-26 22:59:47 +00:00
gettimeofday ( & tv_temp , NULL ) ;
result = np_net_ssl_init_with_hostname_version_and_cert ( sd , ( use_sni ? host_name : NULL ) , ssl_version , client_cert , client_privkey ) ;
2016-11-30 11:36:55 +00:00
if ( verbose ) printf ( " SSL initialized \n " ) ;
2013-11-26 22:58:53 +00:00
if ( result ! = STATE_OK )
2013-11-26 23:01:15 +00:00
die ( STATE_CRITICAL , NULL ) ;
2013-11-26 22:59:47 +00:00
microsec_ssl = deltime ( tv_temp ) ;
elapsed_time_ssl = ( double ) microsec_ssl / 1.0e6 ;
2013-11-26 22:53:19 +00:00
if ( check_cert = = TRUE ) {
2013-11-26 22:59:06 +00:00
result = np_net_ssl_check_cert ( days_till_exp_warn , days_till_exp_crit ) ;
2013-11-26 22:56:50 +00:00
if ( sd ) close ( sd ) ;
2016-11-30 11:36:55 +00:00
np_net_ssl_cleanup ( ) ;
2013-11-26 22:53:19 +00:00
return result ;
}
}
# endif /* HAVE_SSL */
2016-11-30 11:36:55 +00:00
if ( server_address ! = NULL & & strcmp ( http_method , " CONNECT " ) = = 0
& & host_name ! = NULL & & use_ssl = = TRUE )
2020-12-10 20:00:09 +00:00
asprintf ( & buf , " %s %s %s \r \n %s \r \n " , http_method_proxy , server_url , host_name ? " HTTP/1.1 " : " HTTP/1.0 " , user_agent ) ;
2016-11-30 11:36:55 +00:00
else
asprintf ( & buf , " %s %s %s \r \n %s \r \n " , http_method , server_url , host_name ? " HTTP/1.1 " : " HTTP/1.0 " , user_agent ) ;
2013-11-26 22:53:19 +00:00
2013-11-26 22:54:42 +00:00
/* tell HTTP/1.1 servers not to keep the connection alive */
2013-11-26 22:59:47 +00:00
xasprintf ( & buf , " %sConnection: close \r \n " , buf ) ;
2013-11-26 22:54:42 +00:00
2016-11-30 11:36:55 +00:00
/* check if Host header is explicitly set in options */
if ( http_opt_headers_count ) {
for ( i = 0 ; i < http_opt_headers_count ; i + + ) {
if ( strncmp ( http_opt_headers [ i ] , " Host: " , 5 ) = = 0 ) {
force_host_header = http_opt_headers [ i ] ;
}
}
}
2013-11-26 22:53:19 +00:00
/* optionally send the host header info */
2013-11-26 22:56:50 +00:00
if ( host_name ) {
2016-11-30 11:36:55 +00:00
if ( force_host_header ) {
xasprintf ( & buf , " %s%s \r \n " , buf , force_host_header ) ;
}
else {
/*
* Specify the port only if we ' re using a non - default port ( see RFC 2616 ,
* 14.23 ) . Some server applications / configurations cause trouble if the
* ( default ) port is explicitly specified in the " Host: " header line .
*/
if ( ( use_ssl = = FALSE & & virtual_port = = HTTP_PORT ) | |
( use_ssl = = TRUE & & virtual_port = = HTTPS_PORT ) | |
( server_address ! = NULL & & strcmp ( http_method , " CONNECT " ) = = 0
& & host_name ! = NULL & & use_ssl = = TRUE ) )
xasprintf ( & buf , " %sHost: %s \r \n " , buf , host_name ) ;
else
xasprintf ( & buf , " %sHost: %s:%d \r \n " , buf , host_name , virtual_port ) ;
}
2013-11-26 22:56:50 +00:00
}
2013-11-26 22:53:19 +00:00
/* optionally send any other header tag */
if ( http_opt_headers_count ) {
for ( i = 0 ; i < http_opt_headers_count ; i + + ) {
2016-11-30 11:36:55 +00:00
if ( force_host_header ! = http_opt_headers [ i ] ) {
xasprintf ( & buf , " %s%s \r \n " , buf , http_opt_headers [ i ] ) ;
}
2013-11-26 22:53:19 +00:00
}
2013-11-26 22:56:50 +00:00
/* This cannot be free'd here because a redirection will then try to access this and segfault */
/* Covered in a testcase in tests/check_http.t */
/* free(http_opt_headers); */
2013-11-26 22:53:19 +00:00
}
/* optionally send the authentication info */
if ( strlen ( user_auth ) ) {
2013-11-26 22:55:28 +00:00
base64_encode_alloc ( user_auth , strlen ( user_auth ) , & auth ) ;
2013-11-26 22:59:47 +00:00
xasprintf ( & buf , " %sAuthorization: Basic %s \r \n " , buf , auth ) ;
2013-11-26 22:53:19 +00:00
}
2013-11-26 22:57:29 +00:00
/* optionally send the proxy authentication info */
if ( strlen ( proxy_auth ) ) {
base64_encode_alloc ( proxy_auth , strlen ( proxy_auth ) , & auth ) ;
2013-11-26 22:59:47 +00:00
xasprintf ( & buf , " %sProxy-Authorization: Basic %s \r \n " , buf , auth ) ;
2013-11-26 22:57:29 +00:00
}
2013-11-26 22:56:50 +00:00
/* either send http POST data (any data, not only POST)*/
2013-11-26 22:53:19 +00:00
if ( http_post_data ) {
if ( http_content_type ) {
2013-11-26 22:59:47 +00:00
xasprintf ( & buf , " %sContent-Type: %s \r \n " , buf , http_content_type ) ;
2013-11-26 22:53:19 +00:00
} else {
2013-11-26 22:59:47 +00:00
xasprintf ( & buf , " %sContent-Type: application/x-www-form-urlencoded \r \n " , buf ) ;
2013-11-26 22:53:19 +00:00
}
2013-11-26 22:55:28 +00:00
2013-11-26 22:59:47 +00:00
xasprintf ( & buf , " %sContent-Length: %i \r \n \r \n " , buf , ( int ) strlen ( http_post_data ) ) ;
xasprintf ( & buf , " %s%s%s " , buf , http_post_data , CRLF ) ;
2013-11-26 22:53:19 +00:00
}
else {
/* or just a newline so the server knows we're done with the request */
2013-11-26 22:59:47 +00:00
xasprintf ( & buf , " %s%s " , buf , CRLF ) ;
2013-11-26 22:53:19 +00:00
}
if ( verbose ) printf ( " %s \n " , buf ) ;
2013-11-26 22:59:47 +00:00
gettimeofday ( & tv_temp , NULL ) ;
2013-11-26 22:53:19 +00:00
my_send ( buf , strlen ( buf ) ) ;
2013-11-26 22:59:47 +00:00
microsec_headers = deltime ( tv_temp ) ;
elapsed_time_headers = ( double ) microsec_headers / 1.0e6 ;
2013-11-26 22:53:19 +00:00
/* fetch the page */
full_page = strdup ( " " ) ;
2013-11-26 22:59:47 +00:00
gettimeofday ( & tv_temp , NULL ) ;
2013-11-26 22:53:19 +00:00
while ( ( i = my_recv ( buffer , MAX_INPUT_BUFFER - 1 ) ) > 0 ) {
2013-11-26 22:59:47 +00:00
if ( ( i > = 1 ) & & ( elapsed_time_firstbyte < = 0.000001 ) ) {
microsec_firstbyte = deltime ( tv_temp ) ;
elapsed_time_firstbyte = ( double ) microsec_firstbyte / 1.0e6 ;
}
2016-11-30 11:36:55 +00:00
while ( pos = memchr ( buffer , ' \0 ' , i ) ) {
/* replace nul character with a blank */
* pos = ' ' ;
}
2013-11-26 22:53:19 +00:00
buffer [ i ] = ' \0 ' ;
2013-11-26 22:59:47 +00:00
xasprintf ( & full_page_new , " %s%s " , full_page , buffer ) ;
2013-11-26 22:57:29 +00:00
free ( full_page ) ;
full_page = full_page_new ;
2013-11-26 22:53:19 +00:00
pagesize + = i ;
if ( no_body & & document_headers_done ( full_page ) ) {
i = 0 ;
break ;
}
}
2013-11-26 22:59:47 +00:00
microsec_transfer = deltime ( tv_temp ) ;
elapsed_time_transfer = ( double ) microsec_transfer / 1.0e6 ;
2013-11-26 22:53:19 +00:00
if ( i < 0 & & errno ! = ECONNRESET ) {
# ifdef HAVE_SSL
/*
if ( use_ssl ) {
sslerr = SSL_get_error ( ssl , i ) ;
if ( sslerr = = SSL_ERROR_SSL ) {
2013-11-26 22:54:42 +00:00
die ( STATE_WARNING , _ ( " HTTP WARNING - Client Certificate Required \n " ) ) ;
2013-11-26 22:53:19 +00:00
} else {
2013-11-26 22:54:42 +00:00
die ( STATE_CRITICAL , _ ( " HTTP CRITICAL - Error on receive \n " ) ) ;
2013-11-26 22:53:19 +00:00
}
}
else {
*/
# endif
2013-11-26 22:54:42 +00:00
die ( STATE_CRITICAL , _ ( " HTTP CRITICAL - Error on receive \n " ) ) ;
2013-11-26 22:53:19 +00:00
# ifdef HAVE_SSL
/* XXX
}
*/
# endif
}
/* return a CRITICAL status if we couldn't read any data */
if ( pagesize = = ( size_t ) 0 )
2013-11-26 22:54:42 +00:00
die ( STATE_CRITICAL , _ ( " HTTP CRITICAL - No data received from host \n " ) ) ;
2013-11-26 22:53:19 +00:00
/* close the connection */
2016-11-30 11:36:55 +00:00
if ( sd ) close ( sd ) ;
2013-11-26 22:53:19 +00:00
# ifdef HAVE_SSL
np_net_ssl_cleanup ( ) ;
# endif
2013-11-26 22:56:50 +00:00
/* Save check time */
microsec = deltime ( tv ) ;
elapsed_time = ( double ) microsec / 1.0e6 ;
2013-11-26 22:53:19 +00:00
/* leave full_page untouched so we can free it later */
page = full_page ;
if ( verbose )
printf ( " %s://%s:%d%s is %d characters \n " ,
use_ssl ? " https " : " http " , server_address ,
server_port , server_url , ( int ) pagesize ) ;
/* find status line and null-terminate it */
status_line = page ;
page + = ( size_t ) strcspn ( page , " \r \n " ) ;
pos = page ;
page + = ( size_t ) strspn ( page , " \r \n " ) ;
status_line [ strcspn ( status_line , " \r \n " ) ] = 0 ;
strip ( status_line ) ;
if ( verbose )
printf ( " STATUS: %s \n " , status_line ) ;
/* find header info and null-terminate it */
header = page ;
while ( strcspn ( page , " \r \n " ) > 0 ) {
page + = ( size_t ) strcspn ( page , " \r \n " ) ;
pos = page ;
if ( ( strspn ( page , " \r " ) = = 1 & & strspn ( page , " \r \n " ) > = 2 ) | |
( strspn ( page , " \n " ) = = 1 & & strspn ( page , " \r \n " ) > = 2 ) )
page + = ( size_t ) 2 ;
else
page + = ( size_t ) 1 ;
}
page + = ( size_t ) strspn ( page , " \r \n " ) ;
header [ pos - header ] = 0 ;
if ( verbose )
printf ( " **** HEADER **** \n %s \n **** CONTENT **** \n %s \n " , header ,
( no_body ? " [[ skipped ]] " : page ) ) ;
/* make sure the status line matches the response we are looking for */
2013-11-26 22:56:50 +00:00
if ( ! expected_statuscode ( status_line , server_expect ) ) {
2013-11-26 22:53:19 +00:00
if ( server_port = = HTTP_PORT )
2013-11-26 22:59:47 +00:00
xasprintf ( & msg ,
2013-11-26 22:56:50 +00:00
_ ( " Invalid HTTP response received from host: %s \n " ) ,
status_line ) ;
2013-11-26 22:53:19 +00:00
else
2013-11-26 22:59:47 +00:00
xasprintf ( & msg ,
2013-11-26 22:56:50 +00:00
_ ( " Invalid HTTP response received from host on port %d: %s \n " ) ,
server_port , status_line ) ;
2020-12-10 20:00:09 +00:00
if ( show_body )
xasprintf ( & msg , _ ( " %s \n %s " ) , msg , page ) ;
2013-11-26 22:54:42 +00:00
die ( STATE_CRITICAL , " HTTP CRITICAL - %s " , msg ) ;
2013-11-26 22:53:19 +00:00
}
2013-11-26 22:56:50 +00:00
/* Bypass normal status line check if server_expect was set by user and not default */
/* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */
2013-11-26 22:53:19 +00:00
if ( server_expect_yn ) {
2013-11-26 22:59:47 +00:00
xasprintf ( & msg ,
2013-11-26 22:56:50 +00:00
_ ( " Status line output matched \" %s \" - " ) , server_expect ) ;
2013-11-26 22:53:19 +00:00
if ( verbose )
printf ( " %s \n " , msg ) ;
}
else {
/* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
/* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
/* Status-Code = 3 DIGITS */
status_code = strchr ( status_line , ' ' ) + sizeof ( char ) ;
if ( strspn ( status_code , " 1234567890 " ) ! = 3 )
die ( STATE_CRITICAL , _ ( " HTTP CRITICAL: Invalid Status Line (%s) \n " ) , status_line ) ;
http_status = atoi ( status_code ) ;
/* check the return code */
2013-11-26 22:56:50 +00:00
if ( http_status > = 600 | | http_status < 100 ) {
2013-11-26 22:53:19 +00:00
die ( STATE_CRITICAL , _ ( " HTTP CRITICAL: Invalid Status (%s) \n " ) , status_line ) ;
2013-11-26 22:56:50 +00:00
}
2013-11-26 22:53:19 +00:00
/* server errors result in a critical state */
2013-11-26 22:56:50 +00:00
else if ( http_status > = 500 ) {
2013-11-26 22:59:47 +00:00
xasprintf ( & msg , _ ( " %s - " ) , status_line ) ;
2013-11-26 22:56:50 +00:00
result = STATE_CRITICAL ;
}
2013-11-26 22:53:19 +00:00
/* client errors result in a warning state */
2013-11-26 22:56:50 +00:00
else if ( http_status > = 400 ) {
2013-11-26 22:59:47 +00:00
xasprintf ( & msg , _ ( " %s - " ) , status_line ) ;
2013-11-26 22:56:50 +00:00
result = max_state_alt ( STATE_WARNING , result ) ;
}
2013-11-26 22:53:19 +00:00
/* check redirected page if specified */
else if ( http_status > = 300 ) {
if ( onredirect = = STATE_DEPENDENT )
redir ( header , status_line ) ;
2013-11-26 22:56:50 +00:00
else
result = max_state_alt ( onredirect , result ) ;
2013-11-26 22:59:47 +00:00
xasprintf ( & msg , _ ( " %s - " ) , status_line ) ;
2013-11-26 22:53:19 +00:00
} /* end if (http_status >= 300) */
2013-11-26 22:56:50 +00:00
else {
/* Print OK status anyway */
2013-11-26 22:59:47 +00:00
xasprintf ( & msg , _ ( " %s - " ) , status_line ) ;
2013-11-26 22:56:50 +00:00
}
2013-11-26 22:53:19 +00:00
} /* end else (server_expect_yn) */
2013-11-26 22:55:28 +00:00
2013-11-26 22:56:50 +00:00
/* reset the alarm - must be called *after* redir or we'll never die on redirects! */
alarm ( 0 ) ;
2013-11-26 22:53:19 +00:00
2013-11-26 22:56:50 +00:00
if ( maximum_age > = 0 ) {
result = max_state_alt ( check_document_dates ( header , & msg ) , result ) ;
}
2013-11-26 22:53:19 +00:00
/* Page and Header content checks go here */
2013-11-26 22:59:47 +00:00
if ( strlen ( header_expect ) ) {
if ( ! strstr ( header , header_expect ) ) {
strncpy ( & output_header_search [ 0 ] , header_expect , sizeof ( output_header_search ) ) ;
if ( output_header_search [ sizeof ( output_header_search ) - 1 ] ! = ' \0 ' ) {
bcopy ( " ... " , & output_header_search [ sizeof ( output_header_search ) - 4 ] , 4 ) ;
}
xasprintf ( & msg , _ ( " %sheader '%s' not found on '%s://%s:%d%s', " ) , msg , output_header_search , use_ssl ? " https " : " http " , host_name ? host_name : server_address , server_port , server_url ) ;
result = STATE_CRITICAL ;
}
}
2013-11-26 22:53:19 +00:00
if ( strlen ( string_expect ) ) {
2013-11-26 22:56:50 +00:00
if ( ! strstr ( page , string_expect ) ) {
2013-11-26 22:57:29 +00:00
strncpy ( & output_string_search [ 0 ] , string_expect , sizeof ( output_string_search ) ) ;
if ( output_string_search [ sizeof ( output_string_search ) - 1 ] ! = ' \0 ' ) {
bcopy ( " ... " , & output_string_search [ sizeof ( output_string_search ) - 4 ] , 4 ) ;
}
2013-11-26 22:59:47 +00:00
xasprintf ( & msg , _ ( " %sstring '%s' not found on '%s://%s:%d%s', " ) , msg , output_string_search , use_ssl ? " https " : " http " , host_name ? host_name : server_address , server_port , server_url ) ;
2013-11-26 22:56:50 +00:00
result = STATE_CRITICAL ;
2013-11-26 22:53:19 +00:00
}
}
if ( strlen ( regexp ) ) {
errcode = regexec ( & preg , page , REGS , pmatch , 0 ) ;
if ( ( errcode = = 0 & & invert_regex = = 0 ) | | ( errcode = = REG_NOMATCH & & invert_regex = = 1 ) ) {
2013-11-26 22:56:50 +00:00
/* OK - No-op to avoid changing the logic around it */
result = max_state_alt ( STATE_OK , result ) ;
2013-11-26 22:53:19 +00:00
}
else if ( ( errcode = = REG_NOMATCH & & invert_regex = = 0 ) | | ( errcode = = 0 & & invert_regex = = 1 ) ) {
2013-11-26 22:56:50 +00:00
if ( invert_regex = = 0 )
2013-11-26 22:59:47 +00:00
xasprintf ( & msg , _ ( " %spattern not found, " ) , msg ) ;
2013-11-26 22:56:50 +00:00
else
2013-11-26 22:59:47 +00:00
xasprintf ( & msg , _ ( " %spattern found, " ) , msg ) ;
2013-11-26 22:56:50 +00:00
result = STATE_CRITICAL ;
2013-11-26 22:53:19 +00:00
}
else {
2013-11-26 22:56:50 +00:00
/* FIXME: Shouldn't that be UNKNOWN? */
2013-11-26 22:53:19 +00:00
regerror ( errcode , & preg , errbuf , MAX_INPUT_BUFFER ) ;
2013-11-26 22:59:47 +00:00
xasprintf ( & msg , _ ( " %sExecute Error: %s, " ) , msg , errbuf ) ;
2013-11-26 22:56:50 +00:00
result = STATE_CRITICAL ;
2013-11-26 22:53:19 +00:00
}
}
/* make sure the page is of an appropriate size */
/* page_len = get_content_length(header); */
2013-11-26 22:56:50 +00:00
/* FIXME: Will this work with -N ? IMHO we should use
* get_content_length ( header ) and always check if it ' s different than the
* returned pagesize
*/
/* FIXME: IIRC pagesize returns headers - shouldn't we make
* it = = get_content_length ( header ) ? ?
*/
2013-11-26 22:53:19 +00:00
page_len = pagesize ;
if ( ( max_page_len > 0 ) & & ( page_len > max_page_len ) ) {
2013-11-26 22:59:47 +00:00
xasprintf ( & msg , _ ( " %spage size %d too large, " ) , msg , page_len ) ;
2013-11-26 22:56:50 +00:00
result = max_state_alt ( STATE_WARNING , result ) ;
2013-11-26 22:53:19 +00:00
} else if ( ( min_page_len > 0 ) & & ( page_len < min_page_len ) ) {
2013-11-26 22:59:47 +00:00
xasprintf ( & msg , _ ( " %spage size %d too small, " ) , msg , page_len ) ;
2013-11-26 22:56:50 +00:00
result = max_state_alt ( STATE_WARNING , result ) ;
2013-11-26 22:53:19 +00:00
}
2013-11-26 22:56:50 +00:00
/* Cut-off trailing characters */
if ( msg [ strlen ( msg ) - 2 ] = = ' , ' )
msg [ strlen ( msg ) - 2 ] = ' \0 ' ;
else
msg [ strlen ( msg ) - 3 ] = ' \0 ' ;
/* check elapsed time */
2013-11-26 22:59:47 +00:00
if ( show_extended_perfdata )
xasprintf ( & msg ,
_ ( " %s - %d bytes in %.3f second response time %s|%s %s %s %s %s %s %s " ) ,
msg , page_len , elapsed_time ,
( display_html ? " </A> " : " " ) ,
perfd_time ( elapsed_time ) ,
perfd_size ( page_len ) ,
perfd_time_connect ( elapsed_time_connect ) ,
use_ssl = = TRUE ? perfd_time_ssl ( elapsed_time_ssl ) : " " ,
perfd_time_headers ( elapsed_time_headers ) ,
perfd_time_firstbyte ( elapsed_time_firstbyte ) ,
perfd_time_transfer ( elapsed_time_transfer ) ) ;
else
xasprintf ( & msg ,
_ ( " %s - %d bytes in %.3f second response time %s|%s %s " ) ,
msg , page_len , elapsed_time ,
( display_html ? " </A> " : " " ) ,
perfd_time ( elapsed_time ) ,
perfd_size ( page_len ) ) ;
2013-11-26 22:56:50 +00:00
2020-12-10 20:00:09 +00:00
if ( show_body )
xasprintf ( & msg , _ ( " %s \n %s " ) , msg , page ) ;
2013-11-26 22:58:53 +00:00
result = max_state_alt ( get_status ( elapsed_time , thlds ) , result ) ;
2013-11-26 22:56:50 +00:00
die ( result , " HTTP %s: %s \n " , state_text ( result ) , msg ) ;
/* die failed? */
2013-11-26 22:53:19 +00:00
return STATE_UNKNOWN ;
}
/* per RFC 2396 */
2013-11-26 22:54:42 +00:00
# define URI_HTTP "%5[HTPShtps]"
# define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
# define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
2013-11-26 22:53:19 +00:00
# define URI_PATH "%[-_.!~*'(); / ?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
2013-11-26 22:54:42 +00:00
# define HD1 URI_HTTP ": //" URI_HOST ":" URI_PORT "/" URI_PATH
# define HD2 URI_HTTP ": //" URI_HOST "/" URI_PATH
# define HD3 URI_HTTP ": //" URI_HOST ":" URI_PORT
# define HD4 URI_HTTP ": //" URI_HOST
2013-11-26 22:53:19 +00:00
# define HD5 URI_PATH
void
redir ( char * pos , char * status_line )
{
int i = 0 ;
char * x ;
char xx [ 2 ] ;
char type [ 6 ] ;
char * addr ;
char * url ;
addr = malloc ( MAX_IPV4_HOSTLENGTH + 1 ) ;
if ( addr = = NULL )
2013-11-26 22:54:42 +00:00
die ( STATE_UNKNOWN , _ ( " HTTP UNKNOWN - Could not allocate addr \n " ) ) ;
2013-11-26 22:55:28 +00:00
2014-07-11 19:01:00 +00:00
memset ( addr , 0 , MAX_IPV4_HOSTLENGTH ) ;
2013-11-26 22:53:19 +00:00
url = malloc ( strcspn ( pos , " \r \n " ) ) ;
if ( url = = NULL )
2013-11-26 22:56:50 +00:00
die ( STATE_UNKNOWN , _ ( " HTTP UNKNOWN - Could not allocate URL \n " ) ) ;
2013-11-26 22:53:19 +00:00
while ( pos ) {
2013-11-26 22:54:57 +00:00
sscanf ( pos , " %1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n " , xx , & i ) ;
2013-11-26 22:53:19 +00:00
if ( i = = 0 ) {
pos + = ( size_t ) strcspn ( pos , " \r \n " ) ;
pos + = ( size_t ) strspn ( pos , " \r \n " ) ;
2013-11-26 22:56:50 +00:00
if ( strlen ( pos ) = = 0 )
2013-11-26 22:53:19 +00:00
die ( STATE_UNKNOWN ,
2013-11-26 22:54:42 +00:00
_ ( " HTTP UNKNOWN - Could not find redirect location - %s%s \n " ) ,
2013-11-26 22:53:19 +00:00
status_line , ( display_html ? " </A> " : " " ) ) ;
continue ;
}
pos + = i ;
2013-11-26 22:54:42 +00:00
pos + = strspn ( pos , " \t " ) ;
2013-11-26 22:53:19 +00:00
2013-11-26 22:54:42 +00:00
/*
* RFC 2616 ( 4.2 ) : ` ` Header fields can be extended over multiple lines by
* preceding each extra line with at least one SP or HT . ' '
*/
for ( ; ( i = strspn ( pos , " \r \n " ) ) ; pos + = i ) {
pos + = i ;
if ( ! ( i = strspn ( pos , " \t " ) ) ) {
die ( STATE_UNKNOWN , _ ( " HTTP UNKNOWN - Empty redirect location%s \n " ) ,
display_html ? " </A> " : " " ) ;
}
}
url = realloc ( url , strcspn ( pos , " \r \n " ) + 1 ) ;
2013-11-26 22:53:19 +00:00
if ( url = = NULL )
2013-11-26 22:56:50 +00:00
die ( STATE_UNKNOWN , _ ( " HTTP UNKNOWN - Could not allocate URL \n " ) ) ;
2013-11-26 22:53:19 +00:00
/* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
2013-11-26 22:56:50 +00:00
if ( sscanf ( pos , HD1 , type , addr , & i , url ) = = 4 ) {
url = prepend_slash ( url ) ;
2013-11-26 22:53:19 +00:00
use_ssl = server_type_check ( type ) ;
2013-11-26 22:56:50 +00:00
}
2013-11-26 22:53:19 +00:00
/* URI_HTTP URI_HOST URI_PATH */
2013-11-26 22:56:50 +00:00
else if ( sscanf ( pos , HD2 , type , addr , url ) = = 3 ) {
url = prepend_slash ( url ) ;
2013-11-26 22:53:19 +00:00
use_ssl = server_type_check ( type ) ;
i = server_port_check ( use_ssl ) ;
}
/* URI_HTTP URI_HOST URI_PORT */
2013-11-26 22:56:50 +00:00
else if ( sscanf ( pos , HD3 , type , addr , & i ) = = 3 ) {
2013-11-26 22:53:19 +00:00
strcpy ( url , HTTP_URL ) ;
use_ssl = server_type_check ( type ) ;
}
/* URI_HTTP URI_HOST */
2013-11-26 22:56:50 +00:00
else if ( sscanf ( pos , HD4 , type , addr ) = = 2 ) {
2013-11-26 22:53:19 +00:00
strcpy ( url , HTTP_URL ) ;
use_ssl = server_type_check ( type ) ;
i = server_port_check ( use_ssl ) ;
}
/* URI_PATH */
else if ( sscanf ( pos , HD5 , url ) = = 1 ) {
/* relative url */
if ( ( url [ 0 ] ! = ' / ' ) ) {
if ( ( x = strrchr ( server_url , ' / ' ) ) )
* x = ' \0 ' ;
2013-11-26 22:59:47 +00:00
xasprintf ( & url , " %s/%s " , server_url , url ) ;
2013-11-26 22:53:19 +00:00
}
i = server_port ;
strcpy ( type , server_type ) ;
2013-11-26 22:54:57 +00:00
strcpy ( addr , host_name ? host_name : server_address ) ;
2013-11-26 22:56:50 +00:00
}
2013-11-26 22:53:19 +00:00
else {
die ( STATE_UNKNOWN ,
2013-11-26 22:54:42 +00:00
_ ( " HTTP UNKNOWN - Could not parse redirect location - %s%s \n " ) ,
2013-11-26 22:53:19 +00:00
pos , ( display_html ? " </A> " : " " ) ) ;
}
break ;
} /* end while (pos) */
if ( + + redir_depth > max_depth )
die ( STATE_WARNING ,
2013-11-26 22:54:42 +00:00
_ ( " HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s \n " ) ,
2013-11-26 22:53:19 +00:00
max_depth , type , addr , i , url , ( display_html ? " </A> " : " " ) ) ;
if ( server_port = = i & &
2014-07-11 19:01:00 +00:00
! strncmp ( server_address , addr , MAX_IPV4_HOSTLENGTH ) & &
( host_name & & ! strncmp ( host_name , addr , MAX_IPV4_HOSTLENGTH ) ) & &
2013-11-26 22:53:19 +00:00
! strcmp ( server_url , url ) )
die ( STATE_WARNING ,
2013-11-26 22:54:42 +00:00
_ ( " HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s \n " ) ,
2013-11-26 22:53:19 +00:00
type , addr , i , url , ( display_html ? " </A> " : " " ) ) ;
strcpy ( server_type , type ) ;
free ( host_name ) ;
2014-07-11 19:01:00 +00:00
host_name = strndup ( addr , MAX_IPV4_HOSTLENGTH ) ;
2013-11-26 22:53:19 +00:00
2013-11-26 22:56:50 +00:00
if ( ! ( followsticky & STICKY_HOST ) ) {
free ( server_address ) ;
2014-07-11 19:01:00 +00:00
server_address = strndup ( addr , MAX_IPV4_HOSTLENGTH ) ;
2013-11-26 22:56:50 +00:00
}
if ( ! ( followsticky & STICKY_PORT ) ) {
server_port = i ;
}
2013-11-26 22:53:19 +00:00
free ( server_url ) ;
2013-11-26 22:56:50 +00:00
server_url = url ;
2013-11-26 22:54:42 +00:00
2013-11-26 22:56:50 +00:00
if ( server_port > MAX_PORT )
2013-11-26 22:54:42 +00:00
die ( STATE_UNKNOWN ,
_ ( " HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s \n " ) ,
MAX_PORT , server_type , server_address , server_port , server_url ,
display_html ? " </A> " : " " ) ;
2016-11-30 11:36:55 +00:00
/* reset virtual port */
virtual_port = server_port ;
2013-11-26 22:54:42 +00:00
if ( verbose )
2013-11-26 22:54:57 +00:00
printf ( _ ( " Redirection to %s://%s:%d%s \n " ) , server_type ,
host_name ? host_name : server_address , server_port , server_url ) ;
2013-11-26 22:53:19 +00:00
2014-07-11 19:01:00 +00:00
free ( addr ) ;
2013-11-26 22:53:19 +00:00
check_http ( ) ;
}
int
server_type_check ( const char * type )
{
if ( strcmp ( type , " https " ) )
return FALSE ;
else
return TRUE ;
}
int
server_port_check ( int ssl_flag )
{
if ( ssl_flag )
return HTTPS_PORT ;
else
return HTTP_PORT ;
}
char * perfd_time ( double elapsed_time )
{
return fperfdata ( " time " , elapsed_time , " s " ,
2013-11-26 22:58:53 +00:00
thlds - > warning ? TRUE : FALSE , thlds - > warning ? thlds - > warning - > end : 0 ,
thlds - > critical ? TRUE : FALSE , thlds - > critical ? thlds - > critical - > end : 0 ,
2016-11-30 11:36:55 +00:00
TRUE , 0 , TRUE , socket_timeout ) ;
2013-11-26 22:53:19 +00:00
}
2013-11-26 22:59:47 +00:00
char * perfd_time_connect ( double elapsed_time_connect )
{
2016-11-30 11:36:55 +00:00
return fperfdata ( " time_connect " , elapsed_time_connect , " s " , FALSE , 0 , FALSE , 0 , FALSE , 0 , TRUE , socket_timeout ) ;
2013-11-26 22:59:47 +00:00
}
2013-11-26 22:53:19 +00:00
2013-11-26 22:59:47 +00:00
char * perfd_time_ssl ( double elapsed_time_ssl )
{
2016-11-30 11:36:55 +00:00
return fperfdata ( " time_ssl " , elapsed_time_ssl , " s " , FALSE , 0 , FALSE , 0 , FALSE , 0 , TRUE , socket_timeout ) ;
2013-11-26 22:59:47 +00:00
}
char * perfd_time_headers ( double elapsed_time_headers )
{
2016-11-30 11:36:55 +00:00
return fperfdata ( " time_headers " , elapsed_time_headers , " s " , FALSE , 0 , FALSE , 0 , FALSE , 0 , TRUE , socket_timeout ) ;
2013-11-26 22:59:47 +00:00
}
char * perfd_time_firstbyte ( double elapsed_time_firstbyte )
{
2016-11-30 11:36:55 +00:00
return fperfdata ( " time_firstbyte " , elapsed_time_firstbyte , " s " , FALSE , 0 , FALSE , 0 , FALSE , 0 , TRUE , socket_timeout ) ;
2013-11-26 22:59:47 +00:00
}
char * perfd_time_transfer ( double elapsed_time_transfer )
{
2016-11-30 11:36:55 +00:00
return fperfdata ( " time_transfer " , elapsed_time_transfer , " s " , FALSE , 0 , FALSE , 0 , FALSE , 0 , TRUE , socket_timeout ) ;
2013-11-26 22:59:47 +00:00
}
2013-11-26 22:53:19 +00:00
char * perfd_size ( int page_len )
{
return perfdata ( " size " , page_len , " B " ,
( min_page_len > 0 ? TRUE : FALSE ) , min_page_len ,
( min_page_len > 0 ? TRUE : FALSE ) , 0 ,
TRUE , 0 , FALSE , 0 ) ;
}
void
print_help ( void )
{
2013-11-26 22:56:50 +00:00
print_revision ( progname , NP_VERSION ) ;
2013-11-26 22:53:19 +00:00
printf ( " Copyright (c) 1999 Ethan Galstad <nagios@nagios.org> \n " ) ;
printf ( COPYRIGHT , copyright , email ) ;
printf ( " %s \n " , _ ( " This plugin tests the HTTP service on the specified host. It can test " ) ) ;
printf ( " %s \n " , _ ( " normal (http) and secure (https) servers, follow redirects, search for " ) ) ;
printf ( " %s \n " , _ ( " strings and regular expressions, check connection times, and report on " ) ) ;
printf ( " %s \n " , _ ( " certificate expiration times. " ) ) ;
printf ( " \n \n " ) ;
print_usage ( ) ;
printf ( _ ( " NOTE: One or both of -H and -I must be specified " ) ) ;
printf ( " \n " ) ;
2013-11-26 22:57:29 +00:00
printf ( UT_HELP_VRSN ) ;
printf ( UT_EXTRA_OPTS ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s \n " , " -H, --hostname=ADDRESS " ) ;
printf ( " %s \n " , _ ( " Host name argument for servers using host headers (virtual host) " ) ) ;
printf ( " %s \n " , _ ( " Append a port to include it in the header (eg: example.com:5000) " ) ) ;
printf ( " %s \n " , " -I, --IP-address=ADDRESS " ) ;
printf ( " %s \n " , _ ( " IP address or name (use numeric address if possible to bypass DNS lookup). " ) ) ;
printf ( " %s \n " , " -p, --port=INTEGER " ) ;
2013-11-26 22:56:50 +00:00
printf ( " %s " , _ ( " Port number (default: " ) ) ;
2013-11-26 22:53:19 +00:00
printf ( " %d) \n " , HTTP_PORT ) ;
2013-11-26 22:57:29 +00:00
printf ( UT_IPv46 ) ;
2013-11-26 22:53:19 +00:00
# ifdef HAVE_SSL
2016-11-30 11:36:55 +00:00
printf ( " %s \n " , " -S, --ssl=VERSION[+] " ) ;
2013-11-26 22:58:53 +00:00
printf ( " %s \n " , _ ( " Connect via SSL. Port defaults to 443. VERSION is optional, and prevents " ) ) ;
2016-11-30 11:36:55 +00:00
printf ( " %s \n " , _ ( " auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1, " ) ) ;
printf ( " %s \n " , _ ( " 1.2 = TLSv1.2). With a '+' suffix, newer versions are also accepted. " ) ) ;
2013-11-26 22:57:29 +00:00
printf ( " %s \n " , " --sni " ) ;
2013-11-26 22:58:53 +00:00
printf ( " %s \n " , _ ( " Enable SSL/TLS hostname extension support (SNI) " ) ) ;
2013-11-26 22:59:47 +00:00
printf ( " %s \n " , " -C, --certificate=INTEGER[,INTEGER] " ) ;
2013-11-26 22:58:53 +00:00
printf ( " %s \n " , _ ( " Minimum number of days a certificate has to be valid. Port defaults to 443 " ) ) ;
2013-11-26 22:59:47 +00:00
printf ( " %s \n " , _ ( " (when this option is used the URL is not checked.) " ) ) ;
printf ( " %s \n " , " -J, --client-cert=FILE " ) ;
printf ( " %s \n " , _ ( " Name of file that contains the client certificate (PEM format) " ) ) ;
printf ( " %s \n " , _ ( " to be used in establishing the SSL session " ) ) ;
printf ( " %s \n " , " -K, --private-key=FILE " ) ;
printf ( " %s \n " , _ ( " Name of file containing the private key (PEM format) " ) ) ;
printf ( " %s \n " , _ ( " matching the client certificate " ) ) ;
2013-11-26 22:53:19 +00:00
# endif
printf ( " %s \n " , " -e, --expect=STRING " ) ;
2013-11-26 22:56:50 +00:00
printf ( " %s \n " , _ ( " Comma-delimited list of strings, at least one of them is expected in " ) ) ;
printf ( " %s " , _ ( " the first (status) line of the server response (default: " ) ) ;
2013-11-26 22:53:44 +00:00
printf ( " %s) \n " , HTTP_EXPECT ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s \n " , _ ( " If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing) " ) ) ;
2013-11-26 22:59:47 +00:00
printf ( " %s \n " , " -d, --header-string=STRING " ) ;
printf ( " %s \n " , _ ( " String to expect in the response headers " ) ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s \n " , " -s, --string=STRING " ) ;
printf ( " %s \n " , _ ( " String to expect in the content " ) ) ;
printf ( " %s \n " , " -u, --url=PATH " ) ;
printf ( " %s \n " , _ ( " URL to GET or POST (default: /) " ) ) ;
2013-11-26 22:53:44 +00:00
printf ( " %s \n " , " -P, --post=STRING " ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s \n " , _ ( " URL encoded http POST data " ) ) ;
2020-12-10 20:00:09 +00:00
printf ( " %s \n " , " -j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT, CONNECT:POST) " ) ;
2013-11-26 22:56:50 +00:00
printf ( " %s \n " , _ ( " Set HTTP method. " ) ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s \n " , " -N, --no-body " ) ;
printf ( " %s \n " , _ ( " Don't wait for document body: stop reading after headers. " ) ) ;
printf ( " %s \n " , _ ( " (Note that this still does an HTTP GET or POST, not a HEAD.) " ) ) ;
printf ( " %s \n " , " -M, --max-age=SECONDS " ) ;
printf ( " %s \n " , _ ( " Warn if document is more than SECONDS old. the number can also be of " ) ) ;
printf ( " %s \n " , _ ( " the form \" 10m \" for minutes, \" 10h \" for hours, or \" 10d \" for days. " ) ) ;
printf ( " %s \n " , " -T, --content-type=STRING " ) ;
printf ( " %s \n " , _ ( " specify Content-Type header media type when POSTing \n " ) ) ;
printf ( " %s \n " , " -l, --linespan " ) ;
printf ( " %s \n " , _ ( " Allow regex to span newlines (must precede -r or -R) " ) ) ;
printf ( " %s \n " , " -r, --regex, --ereg=STRING " ) ;
printf ( " %s \n " , _ ( " Search page for regex STRING " ) ) ;
printf ( " %s \n " , " -R, --eregi=STRING " ) ;
printf ( " %s \n " , _ ( " Search page for case-insensitive regex STRING " ) ) ;
printf ( " %s \n " , " --invert-regex " ) ;
printf ( " %s \n " , _ ( " Return CRITICAL if found, OK if not \n " ) ) ;
printf ( " %s \n " , " -a, --authorization=AUTH_PAIR " ) ;
printf ( " %s \n " , _ ( " Username:password on sites with basic authentication " ) ) ;
2013-11-26 22:57:29 +00:00
printf ( " %s \n " , " -b, --proxy-authorization=AUTH_PAIR " ) ;
2013-11-26 22:58:53 +00:00
printf ( " %s \n " , _ ( " Username:password on proxy-servers with basic authentication " ) ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s \n " , " -A, --useragent=STRING " ) ;
printf ( " %s \n " , _ ( " String to be sent in http header as \" User Agent \" " ) ) ;
printf ( " %s \n " , " -k, --header=STRING " ) ;
2013-11-26 22:58:53 +00:00
printf ( " %s \n " , _ ( " Any other tags to be sent in http header. Use multiple times for additional headers " ) ) ;
2013-11-26 22:59:47 +00:00
printf ( " %s \n " , " -E, --extended-perfdata " ) ;
printf ( " %s \n " , _ ( " Print additional performance data " ) ) ;
2020-12-10 20:00:09 +00:00
printf ( " %s \n " , " -B, --show-body " ) ;
printf ( " %s \n " , _ ( " Print body content below status line " ) ) ;
2013-11-26 22:53:44 +00:00
printf ( " %s \n " , " -L, --link " ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s \n " , _ ( " Wrap output in HTML link (obsoleted by urlize) " ) ) ;
2013-11-26 22:56:50 +00:00
printf ( " %s \n " , " -f, --onredirect=<ok|warning|critical|follow|sticky|stickyport> " ) ;
printf ( " %s \n " , _ ( " How to handle redirected pages. sticky is like follow but stick to the " ) ) ;
2013-11-26 22:58:53 +00:00
printf ( " %s \n " , _ ( " specified IP address. stickyport also ensures port stays the same. " ) ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s \n " , " -m, --pagesize=INTEGER<:INTEGER> " ) ;
printf ( " %s \n " , _ ( " Minimum page size required (bytes) : Maximum page size required (bytes) " ) ) ;
2013-11-26 22:57:29 +00:00
printf ( UT_WARN_CRIT ) ;
2013-11-26 22:53:19 +00:00
2014-07-11 19:01:00 +00:00
printf ( UT_CONN_TIMEOUT , DEFAULT_SOCKET_TIMEOUT ) ;
2013-11-26 22:53:19 +00:00
2013-11-26 22:57:29 +00:00
printf ( UT_VERBOSE ) ;
2013-11-26 22:53:19 +00:00
2013-11-26 22:55:28 +00:00
printf ( " \n " ) ;
printf ( " %s \n " , _ ( " Notes: " ) ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s \n " , _ ( " This plugin will attempt to open an HTTP connection with the host. " ) ) ;
printf ( " %s \n " , _ ( " Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL " ) ) ;
2020-12-10 20:00:09 +00:00
printf ( " %s \n " , _ ( " other errors return STATE_UNKNOWN. Successful connects, but incorrect response " ) ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s \n " , _ ( " messages from the host result in STATE_WARNING return values. If you are " ) ) ;
printf ( " %s \n " , _ ( " checking a virtual server that uses 'host headers' you must supply the FQDN " ) ) ;
printf ( " %s \n " , _ ( " (fully qualified domain name) as the [host_name] argument. " ) ) ;
# ifdef HAVE_SSL
2013-11-26 22:55:28 +00:00
printf ( " \n " ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s \n " , _ ( " This plugin can also check whether an SSL enabled web server is able to " ) ) ;
printf ( " %s \n " , _ ( " serve content (optionally within a specified time) or whether the X509 " ) ) ;
printf ( " %s \n " , _ ( " certificate is still valid for the specified number of days. " ) ) ;
2013-11-26 22:55:28 +00:00
printf ( " \n " ) ;
2013-11-26 22:58:53 +00:00
printf ( " %s \n " , _ ( " Please note that this plugin does not check if the presented server " ) ) ;
printf ( " %s \n " , _ ( " certificate matches the hostname of the server, or if the certificate " ) ) ;
printf ( " %s \n " , _ ( " has a valid chain of trust to one of the locally installed CAs. " ) ) ;
printf ( " \n " ) ;
2013-11-26 22:55:28 +00:00
printf ( " %s \n " , _ ( " Examples: " ) ) ;
2013-11-26 22:53:44 +00:00
printf ( " %s \n \n " , " CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com " ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s \n " , _ ( " When the 'www.verisign.com' server returns its content within 5 seconds, " ) ) ;
printf ( " %s \n " , _ ( " a STATE_OK will be returned. When the server returns its content but exceeds " ) ) ;
printf ( " %s \n " , _ ( " the 5-second threshold, a STATE_WARNING will be returned. When an error occurs, " ) ) ;
2013-11-26 22:59:47 +00:00
printf ( " %s \n " , _ ( " a STATE_CRITICAL will be returned. " ) ) ;
printf ( " \n " ) ;
2013-11-26 22:53:44 +00:00
printf ( " %s \n \n " , " CHECK CERTIFICATE: check_http -H www.verisign.com -C 14 " ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s \n " , _ ( " When the certificate of 'www.verisign.com' is valid for more than 14 days, " ) ) ;
printf ( " %s \n " , _ ( " a STATE_OK is returned. When the certificate is still valid, but for less than " ) ) ;
printf ( " %s \n " , _ ( " 14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when " ) ) ;
2016-11-30 11:36:55 +00:00
printf ( " %s \n \n " , _ ( " the certificate is expired. " ) ) ;
2013-11-26 22:59:47 +00:00
printf ( " \n " ) ;
2013-11-26 22:59:06 +00:00
printf ( " %s \n \n " , " CHECK CERTIFICATE: check_http -H www.verisign.com -C 30,14 " ) ;
printf ( " %s \n " , _ ( " When the certificate of 'www.verisign.com' is valid for more than 30 days, " ) ) ;
printf ( " %s \n " , _ ( " a STATE_OK is returned. When the certificate is still valid, but for less than " ) ) ;
printf ( " %s \n " , _ ( " 30 days, but more than 14 days, a STATE_WARNING is returned. " ) ) ;
printf ( " %s \n " , _ ( " A STATE_CRITICAL will be returned when certificate expires in less than 14 days " ) ) ;
2016-11-30 11:36:55 +00:00
printf ( " %s \n \n " , " CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: " ) ;
printf ( " %s \n " , _ ( " check_http -I 192.168.100.35 -p 80 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com " ) ) ;
printf ( " %s \n " , _ ( " all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver> " ) ) ;
printf ( " %s \n " , _ ( " a STATE_OK will be returned. When the server returns its content but exceeds " ) ) ;
printf ( " %s \n " , _ ( " the 5-second threshold, a STATE_WARNING will be returned. When an error occurs, " ) ) ;
2020-12-10 20:00:09 +00:00
printf ( " %s \n " , _ ( " a STATE_CRITICAL will be returned. By adding a colon to the method you can set the method used " ) ) ;
printf ( " %s \n " , _ ( " inside the proxied connection: -j CONNECT:POST " ) ) ;
2016-11-30 11:36:55 +00:00
2013-11-26 22:53:19 +00:00
# endif
2013-11-26 22:57:29 +00:00
printf ( UT_SUPPORT ) ;
2013-11-26 22:53:19 +00:00
}
void
print_usage ( void )
{
2013-11-26 22:57:29 +00:00
printf ( " %s \n " , _ ( " Usage: " ) ) ;
2013-11-26 22:53:19 +00:00
printf ( " %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>] \n " , progname ) ;
2013-11-26 22:59:47 +00:00
printf ( " [-J <client certificate file>] [-K <private key>] \n " ) ;
printf ( " [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth] \n " ) ;
2013-11-26 22:57:29 +00:00
printf ( " [-b proxy_auth] [-f <ok|warning|critcal|follow|sticky|stickyport>] \n " ) ;
2013-11-26 22:59:47 +00:00
printf ( " [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] \n " ) ;
2013-11-26 22:56:50 +00:00
printf ( " [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] \n " ) ;
2013-11-26 22:59:06 +00:00
printf ( " [-A string] [-k string] [-S <version>] [--sni] [-C <warn_age>[,<crit_age>]] \n " ) ;
printf ( " [-T <content-type>] [-j method] \n " ) ;
2013-11-26 22:53:19 +00:00
}