2008-01-30 05:53:47 -05:00
/*****************************************************************************
2022-12-22 05:40:19 -05:00
*
* Monitoring check_http plugin
*
* License : GPL
2024-10-31 09:48:54 -04:00
* Copyright ( c ) 1999 - 2024 Monitoring Plugins Development Team
2022-12-22 05:40:19 -05:00
*
* Description :
*
* This file contains the check_http plugin
*
* 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 .
*
*
* 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 < http : //www.gnu.org/licenses/>.
*
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-11-13 12:54:21 -05:00
2003-01-13 07:15:16 -05:00
const char * progname = " check_http " ;
2024-10-31 09:48:54 -04:00
const char * copyright = " 1999-2024 " ;
2014-01-18 03:40:24 -05:00
const char * email = " devel@monitoring-plugins.org " ;
2002-02-28 01:42:51 -05:00
2022-11-13 18:32:44 -05:00
// Do NOT sort those headers, it will break the build
// TODO: Fix this
2002-02-28 01:42:51 -05:00
# include "common.h"
2022-11-13 18:32:44 -05:00
# include "base64.h"
2002-02-28 01:42:51 -05:00
# include "netutils.h"
# include "utils.h"
2022-12-22 05:40:19 -05:00
# include "base64.h"
2008-03-10 20:10:23 -04:00
# include <ctype.h>
2002-02-28 01:42:51 -05:00
2009-03-21 02:32:50 -04:00
# define STICKY_NONE 0
# define STICKY_HOST 1
# define STICKY_PORT 2
2004-11-18 19:12:55 -05:00
2003-08-02 20:01:22 -04:00
# define HTTP_EXPECT "HTTP / 1."
enum {
2005-11-13 20:18:57 -05:00
MAX_IPV4_HOSTLENGTH = 255 ,
HTTP_PORT = 80 ,
2007-06-17 15:22:51 -04:00
HTTPS_PORT = 443 ,
2022-01-29 05:11:36 -05:00
MAX_PORT = 65535 ,
DEFAULT_MAX_REDIRS = 15
2003-08-02 20:01:22 -04:00
} ;
2002-02-28 01:42:51 -05:00
# ifdef HAVE_SSL
2022-11-13 08:47:29 -05:00
bool check_cert = false ;
bool continue_after_check_cert = false ;
2013-12-20 07:46:20 -05:00
int ssl_version = 0 ;
2012-05-21 21:46:45 -04:00
int days_till_exp_warn , days_till_exp_crit ;
2003-08-09 00:19:41 -04:00
char * randbuff ;
2002-02-28 01:42:51 -05:00
X509 * server_cert ;
2022-12-22 05:40:19 -05:00
# 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))
2005-10-19 16:22:00 -04:00
# else /* ifndef HAVE_SSL */
2022-12-22 05:40:19 -05:00
# define my_recv(buf, len) read(sd, buf, len)
# define my_send(buf, len) send(sd, buf, len, 0)
2005-10-19 16:22:00 -04:00
# endif /* HAVE_SSL */
2022-11-13 08:47:29 -05:00
bool no_body = false ;
2004-11-17 18:22:54 -05:00
int maximum_age = - 1 ;
2002-02-28 01:42:51 -05:00
2022-12-22 05:40:19 -05:00
enum {
REGS = 2 ,
MAX_RE_SIZE = 1024
} ;
2006-05-25 08:33:24 -04:00
# include "regex.h"
2002-02-28 01:42:51 -05:00
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 ;
2006-05-25 11:34:54 -04:00
int invert_regex = 0 ;
2024-04-07 14:01:54 -04:00
int state_regex = STATE_CRITICAL ;
2002-02-28 01:42:51 -05:00
2002-10-16 17:32:33 -04:00
struct timeval tv ;
2013-05-19 05:36:06 -04:00
struct timeval tv_temp ;
2002-10-16 17:32:33 -04:00
2002-02-28 01:42:51 -05:00
# define HTTP_URL " / "
2003-01-28 02:15:54 -05:00
# define CRLF "\r\n"
2002-02-28 01:42:51 -05:00
2022-11-13 08:47:29 -05:00
bool specify_port = false ;
2002-02-28 01:42:51 -05:00
int server_port = HTTP_PORT ;
2015-09-15 08:52:18 -04:00
int virtual_port = 0 ;
2002-02-28 01:42:51 -05:00
char server_port_text [ 6 ] = " " ;
char server_type [ 6 ] = " http " ;
2003-08-09 00:19:41 -04:00
char * server_address ;
char * host_name ;
2015-09-15 08:52:18 -04:00
int host_name_length ;
2003-08-09 00:19:41 -04:00
char * server_url ;
2003-08-23 09:59:36 -04:00
char * user_agent ;
2003-02-21 16:59:17 -05:00
int server_url_length ;
2002-06-24 17:29:06 -04:00
int server_expect_yn = 0 ;
2002-02-28 01:42:51 -05:00
char server_expect [ MAX_INPUT_BUFFER ] = HTTP_EXPECT ;
2012-06-07 00:35:34 -04:00
char header_expect [ MAX_INPUT_BUFFER ] = " " ;
2002-02-28 01:42:51 -05:00
char string_expect [ MAX_INPUT_BUFFER ] = " " ;
2011-01-01 15:29:43 -05:00
char * warning_thresholds = NULL ;
char * critical_thresholds = NULL ;
thresholds * thlds ;
2002-02-28 01:42:51 -05:00
char user_auth [ MAX_INPUT_BUFFER ] = " " ;
2009-09-21 21:20:33 -04:00
char proxy_auth [ MAX_INPUT_BUFFER ] = " " ;
2022-11-13 08:47:29 -05:00
bool display_html = false ;
2006-04-05 03:58:29 -04:00
char * * http_opt_headers ;
int http_opt_headers_count = 0 ;
2002-02-28 01:42:51 -05:00
int onredirect = STATE_OK ;
2009-03-21 02:32:50 -04:00
int followsticky = STICKY_NONE ;
2022-11-13 08:47:29 -05:00
bool use_ssl = false ;
bool use_sni = false ;
bool verbose = false ;
bool show_extended_perfdata = false ;
bool show_body = false ;
2002-02-28 01:42:51 -05:00
int sd ;
2003-03-04 19:17:15 -05:00
int min_page_len = 0 ;
2005-01-20 17:50:09 -05:00
int max_page_len = 0 ;
2003-08-21 14:00:48 -04:00
int redir_depth = 0 ;
2022-01-29 05:11:36 -05:00
int max_depth = DEFAULT_MAX_REDIRS ;
2003-08-09 00:19:41 -04:00
char * http_method ;
2018-10-31 10:22:50 -04:00
char * http_method_proxy ;
2003-08-09 00:19:41 -04:00
char * http_post_data ;
2004-02-19 22:21:40 -05:00
char * http_content_type ;
2002-02-28 01:42:51 -05:00
char buffer [ MAX_INPUT_BUFFER ] ;
2013-05-17 09:00:09 -04:00
char * client_cert = NULL ;
char * client_privkey = NULL ;
2002-02-28 01:42:51 -05:00
2022-11-13 17:03:25 -05:00
// Forward function declarations
2022-12-22 05:40:19 -05:00
bool process_arguments ( int , char * * ) ;
int check_http ( void ) ;
void redir ( char * pos , char * status_line ) ;
2022-11-13 08:47:29 -05:00
bool server_type_check ( const char * type ) ;
2003-08-21 14:00:48 -04:00
int server_port_check ( int ssl_flag ) ;
2022-12-22 05:40:19 -05:00
char * perfd_time ( double microsec ) ;
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 ) ;
char * perfd_size ( int page_len ) ;
void print_help ( void ) ;
void print_usage ( void ) ;
2022-11-13 18:33:26 -05:00
char * unchunk_content ( const char * content ) ;
2022-11-13 12:54:21 -05:00
2022-12-22 05:40:19 -05:00
int
main ( int argc , char * * argv )
{
2005-11-13 20:18:57 -05:00
int result = STATE_UNKNOWN ;
2022-12-22 05:40:19 -05:00
setlocale ( LC_ALL , " " ) ;
bindtextdomain ( PACKAGE , LOCALEDIR ) ;
textdomain ( PACKAGE ) ;
2007-12-11 00:57:35 -05:00
2022-12-22 05:40:19 -05:00
/* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
2005-11-13 20:18:57 -05:00
server_url = strdup ( HTTP_URL ) ;
server_url_length = strlen ( server_url ) ;
2022-12-22 05:40:19 -05:00
xasprintf ( & user_agent , " User-Agent: check_http/v%s (monitoring-plugins %s) " ,
2008-11-23 00:38:47 -05:00
NP_VERSION , VERSION ) ;
2005-11-13 20:18:57 -05:00
2009-02-03 04:20:29 -05:00
/* Parse extra opts if any */
2022-12-22 05:40:19 -05:00
argv = np_extra_opts ( & argc , argv , progname ) ;
2008-05-07 06:02:42 -04:00
2022-12-22 05:40:19 -05:00
if ( process_arguments ( argc , argv ) = = false )
usage4 ( _ ( " Could not parse arguments " ) ) ;
2005-11-13 20:18:57 -05:00
2022-11-13 08:47:29 -05:00
if ( display_html = = true )
2022-12-22 05:40:19 -05:00
printf ( " <A HREF= \" %s://%s:%d%s \" target= \" _blank \" > " ,
use_ssl ? " https " : " http " , host_name ? host_name : server_address ,
server_port , server_url ) ;
2005-11-13 20:18:57 -05:00
/* initialize alarm signal handling, set socket timeout, start timer */
2022-12-22 05:40:19 -05:00
( void ) signal ( SIGALRM , socket_timeout_alarm_handler ) ;
( void ) alarm ( socket_timeout ) ;
gettimeofday ( & tv , NULL ) ;
2005-11-13 20:18:57 -05:00
2022-12-22 05:40:19 -05:00
result = check_http ( ) ;
2005-11-13 20:18:57 -05:00
return result ;
2002-02-28 01:42:51 -05:00
}
2004-12-01 18:54:51 -05:00
2013-05-17 09:00:09 -04:00
/* check whether a file exists */
2022-12-22 05:40:19 -05:00
void
test_file ( char * path )
{
2013-05-17 09:00:09 -04:00
if ( access ( path , R_OK ) = = 0 )
return ;
2022-12-22 05:40:19 -05:00
usage2 ( _ ( " file does not exist or is not readable " ) , path ) ;
2013-05-17 09:00:09 -04:00
}
2002-02-28 01:42:51 -05:00
2022-11-13 12:48:26 -05:00
/*
* process command - line arguments
2023-04-14 10:37:47 -04:00
* returns true on success , false otherwise
2022-12-22 05:40:19 -05:00
*/
bool process_arguments ( int argc , char * * argv )
{
2005-11-13 20:18:57 -05:00
int c = 1 ;
2008-01-06 20:59:59 -05:00
char * p ;
2012-05-21 21:46:45 -04:00
char * temp ;
2005-11-13 20:18:57 -05:00
2006-05-25 11:34:54 -04:00
enum {
2010-04-05 21:06:22 -04:00
INVERT_REGEX = CHAR_MAX + 1 ,
2022-01-29 05:11:36 -05:00
SNI_OPTION ,
2022-04-10 10:31:47 -04:00
MAX_REDIRS_OPTION ,
2024-04-07 14:01:54 -04:00
CONTINUE_AFTER_CHECK_CERT ,
STATE_REGEX
2006-05-25 11:34:54 -04:00
} ;
2005-11-13 20:18:57 -05:00
int option = 0 ;
static struct option longopts [ ] = {
2022-12-22 05:40:19 -05:00
STD_LONG_OPTS ,
{ " link " , no_argument , 0 , ' L ' } ,
{ " nohtml " , no_argument , 0 , ' n ' } ,
{ " ssl " , optional_argument , 0 , ' S ' } ,
{ " sni " , no_argument , 0 , SNI_OPTION } ,
{ " post " , required_argument , 0 , ' P ' } ,
{ " method " , required_argument , 0 , ' j ' } ,
{ " IP-address " , required_argument , 0 , ' I ' } ,
{ " url " , required_argument , 0 , ' u ' } ,
{ " port " , required_argument , 0 , ' p ' } ,
{ " authorization " , required_argument , 0 , ' a ' } ,
{ " proxy-authorization " , required_argument , 0 , ' b ' } ,
{ " header-string " , required_argument , 0 , ' d ' } ,
{ " string " , required_argument , 0 , ' s ' } ,
{ " expect " , required_argument , 0 , ' e ' } ,
{ " 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 ' } ,
{ " client-cert " , required_argument , 0 , ' J ' } ,
{ " private-key " , required_argument , 0 , ' K ' } ,
{ " continue-after-certificate " , no_argument , 0 , CONTINUE_AFTER_CHECK_CERT } ,
{ " 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 } ,
2024-04-07 14:01:54 -04:00
{ " state-regex " , required_argument , 0 , STATE_REGEX } ,
2022-12-22 05:40:19 -05:00
{ " use-ipv4 " , no_argument , 0 , ' 4 ' } ,
{ " use-ipv6 " , no_argument , 0 , ' 6 ' } ,
{ " extended-perfdata " , no_argument , 0 , ' E ' } ,
{ " show-body " , no_argument , 0 , ' B ' } ,
{ " max-redirs " , required_argument , 0 , MAX_REDIRS_OPTION } ,
{ 0 , 0 , 0 , 0 }
} ;
2005-11-13 20:18:57 -05:00
if ( argc < 2 )
2022-11-13 08:47:29 -05:00
return false ;
2005-11-13 20:18:57 -05:00
for ( c = 1 ; c < argc ; c + + ) {
2022-12-22 05:40:19 -05:00
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 " ) ;
2005-11-13 20:18:57 -05:00
}
while ( 1 ) {
2022-12-22 05:40:19 -05: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 ) ;
2005-11-13 20:18:57 -05:00
if ( c = = - 1 | | c = = EOF )
break ;
switch ( c ) {
case ' ? ' : /* usage */
2022-12-22 05:40:19 -05:00
usage5 ( ) ;
2005-11-13 20:18:57 -05:00
break ;
case ' h ' : /* help */
2022-12-22 05:40:19 -05:00
print_help ( ) ;
exit ( STATE_UNKNOWN ) ;
2005-11-13 20:18:57 -05:00
break ;
case ' V ' : /* version */
2022-12-22 05:40:19 -05:00
print_revision ( progname , NP_VERSION ) ;
exit ( STATE_UNKNOWN ) ;
2005-11-13 20:18:57 -05:00
break ;
case ' t ' : /* timeout period */
2022-12-22 05:40:19 -05:00
if ( ! is_intnonneg ( optarg ) )
usage2 ( _ ( " Timeout interval must be a positive integer " ) , optarg ) ;
2005-11-13 20:18:57 -05:00
else
2022-12-22 05:40:19 -05:00
socket_timeout = atoi ( optarg ) ;
2005-11-13 20:18:57 -05:00
break ;
case ' c ' : /* critical time threshold */
2011-01-01 15:29:43 -05:00
critical_thresholds = optarg ;
2005-11-13 20:18:57 -05:00
break ;
case ' w ' : /* warning time threshold */
2011-01-01 15:29:43 -05:00
warning_thresholds = optarg ;
2005-11-13 20:18:57 -05:00
break ;
case ' A ' : /* User Agent String */
2022-12-22 05:40:19 -05:00
xasprintf ( & user_agent , " User-Agent: %s " , optarg ) ;
2005-11-13 20:18:57 -05:00
break ;
case ' k ' : /* Additional headers */
2006-04-05 03:58:29 -04:00
if ( http_opt_headers_count = = 0 )
2022-12-22 05:40:19 -05:00
http_opt_headers = malloc ( sizeof ( char * ) * ( + + http_opt_headers_count ) ) ;
2006-04-05 03:58:29 -04:00
else
2022-12-22 05:40:19 -05:00
http_opt_headers = realloc ( http_opt_headers , sizeof ( char * ) * ( + + http_opt_headers_count ) ) ;
2006-04-05 03:58:29 -04:00
http_opt_headers [ http_opt_headers_count - 1 ] = optarg ;
2012-06-29 00:57:48 -04:00
/* xasprintf (&http_opt_headers, "%s", optarg); */
2005-11-13 20:18:57 -05:00
break ;
case ' L ' : /* show html link */
2022-11-13 08:47:29 -05:00
display_html = true ;
2005-11-13 20:18:57 -05:00
break ;
case ' n ' : /* do not show html link */
2022-11-13 08:47:29 -05:00
display_html = false ;
2005-11-13 20:18:57 -05:00
break ;
case ' C ' : /* Check SSL cert validity */
2006-03-24 11:25:46 -05:00
# ifdef HAVE_SSL
2022-12-22 05:40:19 -05:00
if ( ( temp = strchr ( optarg , ' , ' ) ) ! = NULL ) {
* temp = ' \0 ' ;
if ( ! is_intnonneg ( optarg ) )
usage2 ( _ ( " Invalid certificate expiration period " ) , optarg ) ;
2012-07-18 17:39:05 -04:00
days_till_exp_warn = atoi ( optarg ) ;
2022-12-22 05:40:19 -05:00
* temp = ' , ' ;
2012-07-18 17:39:05 -04:00
temp + + ;
2022-12-22 05:40:19 -05:00
if ( ! is_intnonneg ( temp ) )
usage2 ( _ ( " Invalid certificate expiration period " ) , temp ) ;
days_till_exp_crit = atoi ( temp ) ;
}
else {
days_till_exp_crit = 0 ;
if ( ! is_intnonneg ( optarg ) )
usage2 ( _ ( " Invalid certificate expiration period " ) , optarg ) ;
days_till_exp_warn = atoi ( optarg ) ;
2005-11-13 20:18:57 -05:00
}
2022-11-13 08:47:29 -05:00
check_cert = true ;
2013-05-17 09:00:09 -04:00
goto enable_ssl ;
2022-04-10 10:31:47 -04:00
# endif
2022-12-22 05:40:19 -05:00
case CONTINUE_AFTER_CHECK_CERT : /* don't stop after the certificate is checked */
2022-04-10 10:31:47 -04:00
# ifdef HAVE_SSL
2022-11-13 08:47:29 -05:00
continue_after_check_cert = true ;
2022-04-10 10:31:47 -04:00
break ;
2013-05-17 09:00:09 -04:00
# endif
2013-08-18 17:10:31 -04:00
case ' J ' : /* use client certificate */
2013-05-17 09:00:09 -04:00
# 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 ;
2006-03-24 11:25:46 -05:00
# endif
case ' S ' : /* use SSL */
2012-07-18 17:31:17 -04:00
# ifdef HAVE_SSL
2013-05-17 09:00:09 -04:00
enable_ssl :
2022-12-22 05:40:19 -05: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 */
2022-11-13 08:47:29 -05:00
use_ssl = true ;
2022-12-22 05:40:19 -05:00
if ( c = = ' S ' & & optarg ! = NULL ) {
2015-10-04 17:28:35 -04:00
int got_plus = strchr ( optarg , ' + ' ) ! = NULL ;
2022-12-22 05:40:19 -05:00
if ( ! strncmp ( optarg , " 1.2 " , 3 ) )
2015-10-04 17:28:35 -04:00
ssl_version = got_plus ? MP_TLSv1_2_OR_NEWER : MP_TLSv1_2 ;
2022-12-22 05:40:19 -05:00
else if ( ! strncmp ( optarg , " 1.1 " , 3 ) )
2015-10-04 17:28:35 -04:00
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
2022-12-22 05:40:19 -05:00
usage4 ( _ ( " Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with optional '+' suffix) " ) ) ;
2012-05-28 11:16:04 -04:00
}
2022-11-13 08:47:29 -05:00
if ( specify_port = = false )
2006-03-24 11:25:46 -05:00
server_port = HTTPS_PORT ;
2012-07-18 17:31:17 -04:00
# else
2013-08-18 17:10:31 -04:00
/* -C -J and -K fall through to here without SSL */
2022-12-22 05:40:19 -05:00
usage4 ( _ ( " Invalid option - SSL is not available " ) ) ;
2012-07-18 17:31:17 -04:00
# endif
2005-11-13 20:18:57 -05:00
break ;
2010-04-05 21:06:22 -04:00
case SNI_OPTION :
2022-11-13 08:47:29 -05:00
use_sni = true ;
2010-04-05 21:06:22 -04:00
break ;
2022-01-29 05:11:36 -05:00
case MAX_REDIRS_OPTION :
2022-12-22 05:40:19 -05:00
if ( ! is_intnonneg ( optarg ) )
usage2 ( _ ( " Invalid max_redirs count " ) , optarg ) ;
2022-01-29 05:11:36 -05:00
else {
2022-12-22 05:40:19 -05:00
max_depth = atoi ( optarg ) ;
2022-01-29 05:11:36 -05:00
}
2022-12-22 05:40:19 -05:00
break ;
2005-11-13 20:18:57 -05:00
case ' f ' : /* onredirect */
2022-12-22 05:40:19 -05:00
if ( ! strcmp ( optarg , " stickyport " ) )
onredirect = STATE_DEPENDENT , followsticky = STICKY_HOST | STICKY_PORT ;
else if ( ! strcmp ( optarg , " sticky " ) )
2009-03-21 02:32:50 -04:00
onredirect = STATE_DEPENDENT , followsticky = STICKY_HOST ;
2022-12-22 05:40:19 -05:00
else if ( ! strcmp ( optarg , " follow " ) )
2009-03-21 02:32:50 -04:00
onredirect = STATE_DEPENDENT , followsticky = STICKY_NONE ;
2022-12-22 05:40:19 -05:00
else if ( ! strcmp ( optarg , " unknown " ) )
2005-11-13 20:18:57 -05:00
onredirect = STATE_UNKNOWN ;
2022-12-22 05:40:19 -05:00
else if ( ! strcmp ( optarg , " ok " ) )
2005-11-13 20:18:57 -05:00
onredirect = STATE_OK ;
2022-12-22 05:40:19 -05:00
else if ( ! strcmp ( optarg , " warning " ) )
2005-11-13 20:18:57 -05:00
onredirect = STATE_WARNING ;
2022-12-22 05:40:19 -05:00
else if ( ! strcmp ( optarg , " critical " ) )
2005-11-13 20:18:57 -05:00
onredirect = STATE_CRITICAL ;
2022-12-22 05:40:19 -05:00
else usage2 ( _ ( " Invalid onredirect option " ) , optarg ) ;
2005-11-13 20:18:57 -05:00
if ( verbose )
2008-11-19 01:45:18 -05:00
printf ( _ ( " option f:%d \n " ) , onredirect ) ;
2005-11-13 20:18:57 -05:00
break ;
/* Note: H, I, and u must be malloc'd or will fail on redirects */
case ' H ' : /* Host Name (virtual host) */
2022-12-22 05:40:19 -05:00
host_name = strdup ( optarg ) ;
2008-01-06 20:59:59 -05:00
if ( host_name [ 0 ] = = ' [ ' ) {
2022-12-22 05:40:19 -05:00
if ( ( p = strstr ( host_name , " ]: " ) ) ! = NULL ) { /* [IPv6]:port */
virtual_port = atoi ( p + 2 ) ;
2015-09-15 08:52:18 -04:00
/* cut off the port */
2022-12-22 05:40:19 -05:00
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 ;
}
} else if ( ( p = strchr ( host_name , ' : ' ) ) ! = NULL
& & 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 ) ;
2022-11-13 08:47:29 -05:00
if ( specify_port = = false )
2015-09-15 08:52:18 -04:00
server_port = virtual_port ;
}
2005-11-13 20:18:57 -05:00
break ;
case ' I ' : /* Server IP-address */
2022-12-22 05:40:19 -05:00
server_address = strdup ( optarg ) ;
2005-11-13 20:18:57 -05:00
break ;
case ' u ' : /* URL path */
2022-12-22 05:40:19 -05:00
server_url = strdup ( optarg ) ;
server_url_length = strlen ( server_url ) ;
2005-11-13 20:18:57 -05:00
break ;
case ' p ' : /* Server port */
2022-12-22 05:40:19 -05:00
if ( ! is_intnonneg ( optarg ) )
usage2 ( _ ( " Invalid port number " ) , optarg ) ;
2005-11-13 20:18:57 -05:00
else {
2022-12-22 05:40:19 -05:00
server_port = atoi ( optarg ) ;
2022-11-13 08:47:29 -05:00
specify_port = true ;
2005-11-13 20:18:57 -05:00
}
break ;
case ' a ' : /* authorization info */
2022-12-22 05:40:19 -05:00
strncpy ( user_auth , optarg , MAX_INPUT_BUFFER - 1 ) ;
2005-11-13 20:18:57 -05:00
user_auth [ MAX_INPUT_BUFFER - 1 ] = 0 ;
break ;
2009-09-21 21:20:33 -04:00
case ' b ' : /* proxy-authorization info */
2022-12-22 05:40:19 -05:00
strncpy ( proxy_auth , optarg , MAX_INPUT_BUFFER - 1 ) ;
2009-09-21 21:20:33 -04:00
proxy_auth [ MAX_INPUT_BUFFER - 1 ] = 0 ;
break ;
2022-12-22 05:40:19 -05: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 )
2008-11-07 21:08:56 -05:00
http_method = strdup ( " POST " ) ;
break ;
case ' j ' : /* Set HTTP method */
if ( http_method )
free ( http_method ) ;
2022-12-22 05:40:19 -05:00
http_method = strdup ( optarg ) ;
2018-10-31 10:22:50 -04:00
char * tmp ;
2023-10-19 06:20:27 -04:00
if ( ( tmp = strstr ( http_method , " : " ) ) ! = NULL ) {
2023-12-28 18:45:54 -05:00
tmp [ 0 ] = ' \0 ' ; // set the ":" in the middle to 0
http_method_proxy = + + tmp ; // this points to the second part
2018-10-31 10:22:50 -04:00
}
2005-11-13 20:18:57 -05:00
break ;
2012-06-07 00:35:34 -04:00
case ' d ' : /* string or substring */
2022-12-22 05:40:19 -05:00
strncpy ( header_expect , optarg , MAX_INPUT_BUFFER - 1 ) ;
2012-06-07 00:35:34 -04:00
header_expect [ MAX_INPUT_BUFFER - 1 ] = 0 ;
break ;
2005-11-13 20:18:57 -05:00
case ' s ' : /* string or substring */
2022-12-22 05:40:19 -05:00
strncpy ( string_expect , optarg , MAX_INPUT_BUFFER - 1 ) ;
2005-11-13 20:18:57 -05:00
string_expect [ MAX_INPUT_BUFFER - 1 ] = 0 ;
break ;
case ' e ' : /* string or substring */
2022-12-22 05:40:19 -05:00
strncpy ( server_expect , optarg , MAX_INPUT_BUFFER - 1 ) ;
2005-11-13 20:18:57 -05:00
server_expect [ MAX_INPUT_BUFFER - 1 ] = 0 ;
server_expect_yn = 1 ;
break ;
case ' T ' : /* Content-type */
2022-12-22 05:40:19 -05:00
xasprintf ( & http_content_type , " %s " , optarg ) ;
2005-11-13 20:18:57 -05:00
break ;
case ' l ' : /* linespan */
cflags & = ~ REG_NEWLINE ;
break ;
case ' R ' : /* regex */
cflags | = REG_ICASE ;
2023-03-12 14:56:43 -04:00
// fall through
2005-11-13 20:18:57 -05:00
case ' r ' : /* regex */
2022-12-22 05:40:19 -05:00
strncpy ( regexp , optarg , MAX_RE_SIZE - 1 ) ;
2005-11-13 20:18:57 -05:00
regexp [ MAX_RE_SIZE - 1 ] = 0 ;
2022-12-22 05:40:19 -05:00
errcode = regcomp ( & preg , regexp , cflags ) ;
2005-11-13 20:18:57 -05:00
if ( errcode ! = 0 ) {
2022-12-22 05:40:19 -05:00
( void ) regerror ( errcode , & preg , errbuf , MAX_INPUT_BUFFER ) ;
printf ( _ ( " Could Not Compile Regular Expression: %s " ) , errbuf ) ;
2022-11-13 08:47:29 -05:00
return false ;
2005-11-13 20:18:57 -05:00
}
break ;
2006-05-25 11:34:54 -04:00
case INVERT_REGEX :
invert_regex = 1 ;
break ;
2024-04-07 14:01:54 -04:00
case STATE_REGEX :
if ( ! strcmp ( optarg , " critical " ) )
state_regex = STATE_CRITICAL ;
else if ( ! strcmp ( optarg , " warning " ) )
state_regex = STATE_WARNING ;
else usage2 ( _ ( " Invalid state-regex option " ) , optarg ) ;
break ;
2005-11-13 20:18:57 -05:00
case ' 4 ' :
address_family = AF_INET ;
break ;
case ' 6 ' :
2003-06-30 15:47:21 -04:00
# ifdef USE_IPV6
2005-11-13 20:18:57 -05:00
address_family = AF_INET6 ;
2003-06-30 15:47:21 -04:00
# else
2022-12-22 05:40:19 -05:00
usage4 ( _ ( " IPv6 support not available " ) ) ;
2003-06-30 15:47:21 -04:00
# endif
2005-11-13 20:18:57 -05:00
break ;
case ' v ' : /* verbose */
2022-11-13 08:47:29 -05:00
verbose = true ;
2005-11-13 20:18:57 -05:00
break ;
case ' m ' : /* min_page_length */
2022-12-22 05:40:19 -05:00
{
2005-11-13 20:18:57 -05:00
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 " ) ;
2022-12-22 05:40:19 -05:00
exit ( STATE_WARNING ) ;
2005-11-13 20:18:57 -05:00
} else
min_page_len = atoi ( tmp ) ;
tmp = strtok ( NULL , " : " ) ;
if ( tmp = = NULL ) {
printf ( " Bad format: try \" -m min:max \" \n " ) ;
2022-12-22 05:40:19 -05:00
exit ( STATE_WARNING ) ;
2005-11-13 20:18:57 -05:00
} else
max_page_len = atoi ( tmp ) ;
2008-11-19 01:45:18 -05:00
} else
2022-12-22 05:40:19 -05:00
min_page_len = atoi ( optarg ) ;
2005-11-13 20:18:57 -05:00
break ;
2022-12-22 05:40:19 -05:00
}
2005-11-13 20:18:57 -05:00
case ' N ' : /* no-body */
2022-11-13 08:47:29 -05:00
no_body = true ;
2005-11-13 20:18:57 -05:00
break ;
case ' M ' : /* max-age */
2022-12-22 05:40:19 -05:00
{
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-05-19 05:36:06 -04:00
case ' E ' : /* show extended perfdata */
2022-11-13 08:47:29 -05:00
show_extended_perfdata = true ;
2013-05-19 05:36:06 -04:00
break ;
2018-11-09 17:48:56 -05:00
case ' B ' : /* print body content after status line */
2022-11-13 08:47:29 -05:00
show_body = true ;
2018-11-09 17:48:56 -05:00
break ;
2005-11-13 20:18:57 -05:00
}
}
2002-02-28 01:42:51 -05:00
2005-11-13 20:18:57 -05:00
c = optind ;
2002-02-28 01:42:51 -05:00
2005-11-13 20:18:57 -05:00
if ( server_address = = NULL & & c < argc )
2022-12-22 05:40:19 -05:00
server_address = strdup ( argv [ c + + ] ) ;
2002-02-28 01:42:51 -05:00
2005-11-13 20:18:57 -05:00
if ( host_name = = NULL & & c < argc )
2022-12-22 05:40:19 -05:00
host_name = strdup ( argv [ c + + ] ) ;
2002-02-28 01:42:51 -05:00
2005-11-13 20:18:57 -05:00
if ( server_address = = NULL ) {
if ( host_name = = NULL )
2022-12-22 05:40:19 -05:00
usage4 ( _ ( " You must specify a server address or host name " ) ) ;
2005-11-13 20:18:57 -05:00
else
2022-12-22 05:40:19 -05:00
server_address = strdup ( host_name ) ;
2005-11-13 20:18:57 -05:00
}
2002-02-28 01:42:51 -05:00
2011-01-01 15:29:43 -05:00
set_thresholds ( & thlds , warning_thresholds , critical_thresholds ) ;
2022-12-22 05:40:19 -05:00
if ( critical_thresholds & & thlds - > critical - > end > ( double ) socket_timeout )
2011-01-01 15:29:43 -05:00
socket_timeout = ( int ) thlds - > critical - > end + 1 ;
2003-04-07 07:39:04 -04:00
2005-11-13 20:18:57 -05:00
if ( http_method = = NULL )
2022-12-22 05:40:19 -05:00
http_method = strdup ( " GET " ) ;
2003-08-09 00:19:41 -04:00
2018-10-31 10:22:50 -04:00
if ( http_method_proxy = = NULL )
2022-12-22 05:40:19 -05:00
http_method_proxy = strdup ( " GET " ) ;
2018-10-31 10:22:50 -04:00
2015-09-15 08:52:18 -04:00
if ( client_cert & & ! client_privkey )
2022-12-22 05:40:19 -05:00
usage4 ( _ ( " If you use a client certificate you must also specify a private key file " ) ) ;
2013-05-17 09:00:09 -04:00
2015-09-15 08:52:18 -04:00
if ( virtual_port = = 0 )
virtual_port = server_port ;
2022-11-13 08:47:29 -05:00
return true ;
2002-02-28 01:42:51 -05:00
}
2004-12-01 18:54:51 -05:00
2022-12-22 05:40:19 -05:00
2004-11-17 18:22:54 -05:00
/* Returns 1 if we're done processing the document body; 0 to keep going */
2022-12-22 05:40:19 -05:00
static int
document_headers_done ( char * full_page )
{
2005-11-13 20:18:57 -05:00
const char * body ;
2004-11-17 18:22:54 -05:00
2005-11-13 20:18:57 -05:00
for ( body = full_page ; * body ; body + + ) {
2022-12-22 05:40:19 -05:00
if ( ! strncmp ( body , " \n \n " , 2 ) | | ! strncmp ( body , " \n \r \n " , 3 ) )
2005-11-13 20:18:57 -05:00
break ;
}
2004-11-17 18:22:54 -05:00
2005-11-13 20:18:57 -05:00
if ( ! * body )
2022-12-22 05:40:19 -05:00
return 0 ; /* haven't read end of headers yet */
2004-11-17 18:22:54 -05:00
2005-11-13 20:18:57 -05:00
full_page [ body - full_page ] = 0 ;
return 1 ;
2004-11-17 18:22:54 -05:00
}
2022-12-22 05:40:19 -05:00
static time_t
parse_time_string ( const char * string )
{
2005-11-13 20:18:57 -05:00
struct tm tm ;
time_t t ;
2022-12-22 05:40:19 -05:00
memset ( & tm , 0 , sizeof ( tm ) ) ;
2005-11-13 20:18:57 -05:00
/* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
2022-12-22 05:40:19 -05:00
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? */
2005-11-13 20:18:57 -05:00
if ( tm . tm_mon < 0 | | tm . tm_mday < 1 | | tm . tm_mday > 31 )
return 0 ;
2008-11-19 01:45:18 -05:00
/*
2005-11-13 20:18:57 -05: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 .
*/
2022-12-22 05:40:19 -05:00
t = mktime ( & tm ) ;
if ( t = = ( time_t ) - 1 ) t = 0 ;
2005-11-13 20:18:57 -05:00
if ( verbose ) {
const char * s = string ;
while ( * s & & * s ! = ' \r ' & & * s ! = ' \n ' )
2022-12-22 05:40:19 -05:00
fputc ( * s + + , stdout ) ;
printf ( " ==> %lu \n " , ( unsigned long ) t ) ;
2005-11-13 20:18:57 -05:00
}
return t ;
} else {
return 0 ;
}
2004-11-17 18:22:54 -05:00
}
2008-08-25 07:42:57 -04:00
/* Checks if the server 'reply' is one of the expected 'statuscodes' */
2022-12-22 05:40:19 -05:00
static int
expected_statuscode ( const char * reply , const char * statuscodes )
{
2008-08-25 07:42:57 -04:00
char * expected , * code ;
int result = 0 ;
2022-12-22 05:40:19 -05:00
if ( ( expected = strdup ( statuscodes ) ) = = NULL )
die ( STATE_UNKNOWN , _ ( " HTTP UNKNOWN - Memory allocation error \n " ) ) ;
2008-08-25 07:42:57 -04:00
2022-12-22 05:40:19 -05:00
for ( code = strtok ( expected , " , " ) ; code ! = NULL ; code = strtok ( NULL , " , " ) )
if ( strstr ( reply , code ) ! = NULL ) {
2008-08-25 07:42:57 -04:00
result = 1 ;
break ;
}
2004-11-17 18:22:54 -05:00
2022-12-22 05:40:19 -05:00
free ( expected ) ;
2008-08-25 07:42:57 -04:00
return result ;
}
2004-12-01 18:54:51 -05:00
2022-12-22 05:40:19 -05:00
static int
check_document_dates ( const char * headers , char * * msg )
{
2005-11-13 20:18:57 -05:00
const char * s ;
char * server_date = 0 ;
char * document_date = 0 ;
2009-02-03 04:20:29 -05:00
int date_result = STATE_OK ;
2005-11-13 20:18:57 -05: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 + + ;
2008-05-30 19:38:00 -04:00
/* Avoid stepping over end-of-string marker */
if ( * s )
s + + ;
2005-11-13 20:18:57 -05:00
/* Process this header. */
2022-12-22 05:40:19 -05:00
if ( value & & value > field + 2 ) {
char * ff = ( char * ) malloc ( value - field ) ;
2005-11-13 20:18:57 -05:00
char * ss = ff ;
2022-12-22 05:40:19 -05:00
while ( field < value - 1 )
2005-11-13 20:18:57 -05:00
* ss + + = tolower ( * field + + ) ;
* ss + + = 0 ;
2022-12-22 05:40:19 -05:00
if ( ! strcmp ( ff , " date " ) | | ! strcmp ( ff , " last-modified " ) ) {
2005-11-13 20:18:57 -05:00
const char * e ;
2022-12-22 05:40:19 -05:00
while ( * value & & isspace ( * value ) )
2005-11-13 20:18:57 -05:00
value + + ;
for ( e = value ; * e & & * e ! = ' \r ' & & * e ! = ' \n ' ; e + + )
;
2022-12-22 05:40:19 -05:00
ss = ( char * ) malloc ( e - value + 1 ) ;
strncpy ( ss , value , e - value ) ;
2005-11-13 20:18:57 -05:00
ss [ e - value ] = 0 ;
2022-12-22 05:40:19 -05:00
if ( ! strcmp ( ff , " date " ) ) {
if ( server_date ) free ( server_date ) ;
2005-11-13 20:18:57 -05:00
server_date = ss ;
} else {
2022-12-22 05:40:19 -05:00
if ( document_date ) free ( document_date ) ;
2005-11-13 20:18:57 -05:00
document_date = ss ;
}
}
2022-12-22 05:40:19 -05:00
free ( ff ) ;
2005-11-13 20:18:57 -05:00
}
}
/* Done parsing the body. Now check the dates we (hopefully) parsed. */
if ( ! server_date | | ! * server_date ) {
2022-12-22 05:40:19 -05:00
xasprintf ( msg , _ ( " %sServer date unknown, " ) , * msg ) ;
2009-02-03 04:20:29 -05:00
date_result = max_state_alt ( STATE_UNKNOWN , date_result ) ;
2005-11-13 20:18:57 -05:00
} else if ( ! document_date | | ! * document_date ) {
2022-12-22 05:40:19 -05:00
xasprintf ( msg , _ ( " %sDocument modification date unknown, " ) , * msg ) ;
2009-02-03 04:20:29 -05:00
date_result = max_state_alt ( STATE_CRITICAL , date_result ) ;
2005-11-13 20:18:57 -05:00
} else {
2022-12-22 05:40:19 -05:00
time_t srv_data = parse_time_string ( server_date ) ;
time_t doc_data = parse_time_string ( document_date ) ;
2005-11-13 20:18:57 -05:00
if ( srv_data < = 0 ) {
2022-12-22 05:40:19 -05:00
xasprintf ( msg , _ ( " %sServer date \" %100s \" unparsable, " ) , * msg , server_date ) ;
2009-02-03 04:20:29 -05:00
date_result = max_state_alt ( STATE_CRITICAL , date_result ) ;
2005-11-13 20:18:57 -05:00
} else if ( doc_data < = 0 ) {
2022-12-22 05:40:19 -05:00
xasprintf ( msg , _ ( " %sDocument date \" %100s \" unparsable, " ) , * msg , document_date ) ;
2009-02-03 04:20:29 -05:00
date_result = max_state_alt ( STATE_CRITICAL , date_result ) ;
2005-11-13 20:18:57 -05:00
} else if ( doc_data > srv_data + 30 ) {
2022-12-22 05:40:19 -05:00
xasprintf ( msg , _ ( " %sDocument is %d seconds in the future, " ) , * msg , ( int ) doc_data - ( int ) srv_data ) ;
2009-02-03 04:20:29 -05:00
date_result = max_state_alt ( STATE_CRITICAL , date_result ) ;
2005-11-13 20:18:57 -05:00
} else if ( doc_data < srv_data - maximum_age ) {
2009-02-03 04:20:29 -05:00
int n = ( srv_data - doc_data ) ;
if ( n > ( 60 * 60 * 24 * 2 ) ) {
2022-12-22 05:40:19 -05:00
xasprintf ( msg , _ ( " %sLast modified %.1f days ago, " ) , * msg , ( ( float ) n ) / ( 60 * 60 * 24 ) ) ;
2009-02-03 04:20:29 -05:00
date_result = max_state_alt ( STATE_CRITICAL , date_result ) ;
} else {
2022-12-22 05:40:19 -05:00
xasprintf ( msg , _ ( " %sLast modified %d:%02d:%02d ago, " ) , * msg , n / ( 60 * 60 ) , ( n / 60 ) % 60 , n % 60 ) ;
2009-02-03 04:20:29 -05:00
date_result = max_state_alt ( STATE_CRITICAL , date_result ) ;
}
2004-11-17 18:22:54 -05:00
}
2022-12-22 05:40:19 -05:00
free ( server_date ) ;
free ( document_date ) ;
2004-11-17 18:22:54 -05:00
}
2009-02-03 04:20:29 -05:00
return date_result ;
2004-11-17 18:22:54 -05:00
}
2022-12-22 05:40:19 -05:00
int
get_content_length ( const char * headers )
{
2005-11-13 20:18:57 -05:00
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 + + ;
2010-04-11 05:05:49 -04:00
/* Avoid stepping over end-of-string marker */
if ( * s )
s + + ;
2005-11-13 20:18:57 -05:00
/* Process this header. */
2022-12-22 05:40:19 -05:00
if ( value & & value > field + 2 ) {
char * ff = ( char * ) malloc ( value - field ) ;
2005-11-13 20:18:57 -05:00
char * ss = ff ;
2022-12-22 05:40:19 -05:00
while ( field < value - 1 )
2005-11-13 20:18:57 -05:00
* ss + + = tolower ( * field + + ) ;
* ss + + = 0 ;
2022-12-22 05:40:19 -05:00
if ( ! strcmp ( ff , " content-length " ) ) {
2005-11-13 20:18:57 -05:00
const char * e ;
2022-12-22 05:40:19 -05:00
while ( * value & & isspace ( * value ) )
2005-11-13 20:18:57 -05:00
value + + ;
for ( e = value ; * e & & * e ! = ' \r ' & & * e ! = ' \n ' ; e + + )
;
2022-12-22 05:40:19 -05:00
ss = ( char * ) malloc ( e - value + 1 ) ;
strncpy ( ss , value , e - value ) ;
2005-11-13 20:18:57 -05:00
ss [ e - value ] = 0 ;
content_length = atoi ( ss ) ;
2022-12-22 05:40:19 -05:00
free ( ss ) ;
2005-11-13 20:18:57 -05:00
}
2022-12-22 05:40:19 -05:00
free ( ff ) ;
2005-11-13 20:18:57 -05:00
}
}
return ( content_length ) ;
2005-01-20 17:50:09 -05:00
}
2004-11-17 18:22:54 -05:00
2022-12-22 05:40:19 -05:00
char *
prepend_slash ( char * path )
{
2008-09-01 08:20:32 -04:00
char * newpath ;
if ( path [ 0 ] = = ' / ' )
return path ;
2022-12-22 05:40:19 -05:00
if ( ( newpath = malloc ( strlen ( path ) + 2 ) ) = = NULL )
die ( STATE_UNKNOWN , _ ( " HTTP UNKNOWN - Memory allocation error \n " ) ) ;
2008-09-01 08:20:32 -04:00
newpath [ 0 ] = ' / ' ;
2022-12-22 05:40:19 -05:00
strcpy ( newpath + 1 , path ) ;
free ( path ) ;
2008-09-01 08:20:32 -04:00
return newpath ;
}
2022-12-22 05:40:19 -05:00
int
check_http ( void )
{
2005-11-13 20:18:57 -05:00
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 ;
2010-02-26 07:47:38 -05:00
char * full_page_new ;
2005-11-13 20:18:57 -05:00
char * buf ;
char * pos ;
2013-09-10 14:52:13 -04: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 ;
2005-11-13 20:18:57 -05:00
int page_len = 0 ;
2009-02-03 04:20:29 -05:00
int result = STATE_OK ;
2014-10-30 09:40:29 -04:00
char * force_host_header = NULL ;
2005-11-13 20:18:57 -05:00
/* try to connect to the host at the given port number */
2022-12-22 05:40:19 -05:00
gettimeofday ( & tv_temp , NULL ) ;
if ( my_tcp_connect ( server_address , server_port , & sd ) ! = STATE_OK )
die ( STATE_CRITICAL , _ ( " HTTP CRITICAL - Unable to open TCP socket \n " ) ) ;
microsec_connect = deltime ( tv_temp ) ;
2015-08-27 11:09:15 -04:00
2022-12-22 05:40:19 -05: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 */
2015-08-27 11:09:15 -04:00
2022-12-22 05:40:19 -05:00
if ( server_address ! = NULL & & strcmp ( http_method , " CONNECT " ) = = 0
& & host_name ! = NULL & & use_ssl = = true ) {
2015-08-27 11:09:15 -04:00
2022-12-22 05:40:19 -05:00
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 ) ;
2017-10-17 09:19:43 -04:00
if ( strlen ( proxy_auth ) ) {
2022-12-22 05:40:19 -05:00
base64_encode_alloc ( proxy_auth , strlen ( proxy_auth ) , & auth ) ;
xasprintf ( & buf , " %sProxy-Authorization: Basic %s \r \n " , buf , auth ) ;
2017-10-17 09:19:43 -04:00
}
/* optionally send any other header tag */
if ( http_opt_headers_count ) {
2022-12-22 05:40:19 -05:00
for ( i = 0 ; i < http_opt_headers_count ; i + + ) {
2017-10-17 09:19:43 -04:00
if ( force_host_header ! = http_opt_headers [ i ] ) {
2022-12-22 05:40:19 -05:00
xasprintf ( & buf , " %s%s \r \n " , buf , http_opt_headers [ i ] ) ;
2017-10-17 09:19:43 -04:00
}
}
2022-12-22 05:40:19 -05:00
/* This cannot be free'd here because a redirection will then try to access this and segfault */
2017-10-17 09:19:43 -04:00
/* Covered in a testcase in tests/check_http.t */
/* free(http_opt_headers); */
}
2022-12-22 05:40:19 -05:00
asprintf ( & buf , " %sProxy-Connection: keep-alive \r \n " , buf ) ;
asprintf ( & buf , " %sHost: %s \r \n " , buf , host_name ) ;
2015-08-27 11:09:15 -04:00
/* we finished our request, send empty line with CRLF */
2022-12-22 05:40:19 -05:00
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 ) ;
2015-08-27 11:09:15 -04:00
/* Here we should check if we got HTTP/1.1 200 Connection established */
}
2002-02-28 01:42:51 -05:00
# ifdef HAVE_SSL
2013-05-19 05:36:06 -04:00
elapsed_time_connect = ( double ) microsec_connect / 1.0e6 ;
2022-11-13 08:47:29 -05:00
if ( use_ssl = = true ) {
2022-12-22 05:40:19 -05: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 ) ;
if ( verbose ) printf ( " SSL initialized \n " ) ;
2012-05-28 15:42:48 -04:00
if ( result ! = STATE_OK )
2022-12-22 05:40:19 -05:00
die ( STATE_CRITICAL , NULL ) ;
microsec_ssl = deltime ( tv_temp ) ;
2013-05-19 05:36:06 -04:00
elapsed_time_ssl = ( double ) microsec_ssl / 1.0e6 ;
2022-11-13 08:47:29 -05:00
if ( check_cert = = true ) {
2012-05-21 21:46:45 -04:00
result = np_net_ssl_check_cert ( days_till_exp_warn , days_till_exp_crit ) ;
2022-11-13 08:47:29 -05:00
if ( continue_after_check_cert = = false ) {
2022-12-22 05:40:19 -05:00
if ( sd ) close ( sd ) ;
2022-04-10 10:31:47 -04:00
np_net_ssl_cleanup ( ) ;
return result ;
}
2005-11-13 20:18:57 -05:00
}
}
2005-10-19 16:22:00 -04:00
# endif /* HAVE_SSL */
2002-02-28 01:42:51 -05:00
2022-12-22 05:40:19 -05:00
if ( server_address ! = NULL & & strcmp ( http_method , " CONNECT " ) = = 0
& & host_name ! = NULL & & use_ssl = = true )
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 ) ;
2015-08-27 11:09:15 -04:00
else
2022-12-22 05:40:19 -05:00
asprintf ( & buf , " %s %s %s \r \n %s \r \n " , http_method , server_url , host_name ? " HTTP/1.1 " : " HTTP/1.0 " , user_agent ) ;
2005-11-13 20:18:57 -05:00
2007-07-21 12:29:01 -04:00
/* tell HTTP/1.1 servers not to keep the connection alive */
2022-12-22 05:40:19 -05:00
xasprintf ( & buf , " %sConnection: close \r \n " , buf ) ;
2007-07-21 12:29:01 -04:00
2014-10-30 09:40:29 -04:00
/* check if Host header is explicitly set in options */
if ( http_opt_headers_count ) {
2022-12-22 05:40:19 -05:00
for ( i = 0 ; i < http_opt_headers_count ; i + + ) {
2015-05-03 04:32:56 -04:00
if ( strncmp ( http_opt_headers [ i ] , " Host: " , 5 ) = = 0 ) {
2014-10-30 09:40:29 -04:00
force_host_header = http_opt_headers [ i ] ;
}
}
}
2008-09-01 10:04:04 -04:00
/* optionally send the host header info */
2008-09-02 07:26:31 -04:00
if ( host_name ) {
2014-10-30 09:40:29 -04:00
if ( force_host_header ) {
2022-12-22 05:40:19 -05:00
xasprintf ( & buf , " %s%s \r \n " , buf , force_host_header ) ;
}
else {
2014-10-30 09:40:29 -04:00
/*
* 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 .
*/
2022-11-13 08:47:29 -05:00
if ( ( use_ssl = = false & & virtual_port = = HTTP_PORT ) | |
( use_ssl = = true & & virtual_port = = HTTPS_PORT ) | |
2022-12-22 05:40:19 -05:00
( server_address ! = NULL & & strcmp ( http_method , " CONNECT " ) = = 0
& & host_name ! = NULL & & use_ssl = = true ) )
xasprintf ( & buf , " %sHost: %s \r \n " , buf , host_name ) ;
2014-10-30 09:40:29 -04:00
else
2022-12-22 05:40:19 -05:00
xasprintf ( & buf , " %sHost: %s:%d \r \n " , buf , host_name , virtual_port ) ;
2014-10-30 09:40:29 -04:00
}
2008-09-02 07:26:31 -04:00
}
2008-09-01 10:04:04 -04:00
2005-11-13 20:18:57 -05:00
/* optionally send any other header tag */
2006-04-05 03:58:29 -04:00
if ( http_opt_headers_count ) {
2022-12-22 05:40:19 -05:00
for ( i = 0 ; i < http_opt_headers_count ; i + + ) {
2014-10-30 09:40:29 -04:00
if ( force_host_header ! = http_opt_headers [ i ] ) {
2022-12-22 05:40:19 -05:00
xasprintf ( & buf , " %s%s \r \n " , buf , http_opt_headers [ i ] ) ;
2014-10-30 09:40:29 -04:00
}
2006-04-05 03:58:29 -04:00
}
2022-12-22 05:40:19 -05:00
/* This cannot be free'd here because a redirection will then try to access this and segfault */
2008-11-07 21:32:03 -05:00
/* Covered in a testcase in tests/check_http.t */
/* free(http_opt_headers); */
2005-11-13 20:18:57 -05:00
}
/* optionally send the authentication info */
if ( strlen ( user_auth ) ) {
2022-12-22 05:40:19 -05:00
base64_encode_alloc ( user_auth , strlen ( user_auth ) , & auth ) ;
xasprintf ( & buf , " %sAuthorization: Basic %s \r \n " , buf , auth ) ;
2005-11-13 20:18:57 -05:00
}
2009-09-21 21:20:33 -04:00
/* optionally send the proxy authentication info */
if ( strlen ( proxy_auth ) ) {
2022-12-22 05:40:19 -05:00
base64_encode_alloc ( proxy_auth , strlen ( proxy_auth ) , & auth ) ;
xasprintf ( & buf , " %sProxy-Authorization: Basic %s \r \n " , buf , auth ) ;
2009-09-21 21:20:33 -04:00
}
2008-11-07 21:08:56 -05:00
/* either send http POST data (any data, not only POST)*/
2005-11-13 20:18:57 -05:00
if ( http_post_data ) {
if ( http_content_type ) {
2022-12-22 05:40:19 -05:00
xasprintf ( & buf , " %sContent-Type: %s \r \n " , buf , http_content_type ) ;
2005-11-13 20:18:57 -05:00
} else {
2022-12-22 05:40:19 -05:00
xasprintf ( & buf , " %sContent-Type: application/x-www-form-urlencoded \r \n " , buf ) ;
2005-11-13 20:18:57 -05:00
}
2008-04-27 10:35:26 -04:00
2022-12-22 05:40:19 -05:00
xasprintf ( & buf , " %sContent-Length: %i \r \n \r \n " , buf , ( int ) strlen ( http_post_data ) ) ;
xasprintf ( & buf , " %s%s " , buf , http_post_data ) ;
2022-11-05 08:59:45 -04:00
} else {
2005-11-13 20:18:57 -05:00
/* or just a newline so the server knows we're done with the request */
2022-12-22 05:40:19 -05:00
xasprintf ( & buf , " %s%s " , buf , CRLF ) ;
2005-11-13 20:18:57 -05:00
}
2022-12-22 05:40:19 -05:00
if ( verbose ) printf ( " %s \n " , buf ) ;
gettimeofday ( & tv_temp , NULL ) ;
my_send ( buf , strlen ( buf ) ) ;
microsec_headers = deltime ( tv_temp ) ;
2013-05-19 05:36:06 -04:00
elapsed_time_headers = ( double ) microsec_headers / 1.0e6 ;
2005-11-13 20:18:57 -05:00
/* fetch the page */
full_page = strdup ( " " ) ;
2022-12-22 05:40:19 -05:00
gettimeofday ( & tv_temp , NULL ) ;
while ( ( i = my_recv ( buffer , MAX_INPUT_BUFFER - 1 ) ) > 0 ) {
2013-05-19 05:36:06 -04:00
if ( ( i > = 1 ) & & ( elapsed_time_firstbyte < = 0.000001 ) ) {
2022-12-22 05:40:19 -05:00
microsec_firstbyte = deltime ( tv_temp ) ;
2013-05-19 05:36:06 -04:00
elapsed_time_firstbyte = ( double ) microsec_firstbyte / 1.0e6 ;
}
2023-10-15 18:44:08 -04:00
while ( ( pos = memchr ( buffer , ' \0 ' , i ) ) ) {
2015-11-04 10:18:37 -05:00
/* replace nul character with a blank */
* pos = ' ' ;
}
2005-11-13 20:18:57 -05:00
buffer [ i ] = ' \0 ' ;
2022-12-21 08:48:11 -05:00
if ( ( full_page_new = realloc ( full_page , pagesize + i + 1 ) ) = = NULL )
die ( STATE_UNKNOWN , _ ( " HTTP UNKNOWN - Could not allocate memory for full_page \n " ) ) ;
memmove ( & full_page_new [ pagesize ] , buffer , i + 1 ) ;
2010-02-26 07:47:38 -05:00
full_page = full_page_new ;
2022-12-21 08:48:11 -05:00
2005-11-13 20:18:57 -05:00
pagesize + = i ;
2004-11-17 18:22:54 -05:00
2022-12-22 05:40:19 -05:00
if ( no_body & & document_headers_done ( full_page ) ) {
i = 0 ;
break ;
}
2005-11-13 20:18:57 -05:00
}
2022-12-22 05:40:19 -05:00
microsec_transfer = deltime ( tv_temp ) ;
2013-05-19 05:36:06 -04:00
elapsed_time_transfer = ( double ) microsec_transfer / 1.0e6 ;
2002-02-28 01:42:51 -05:00
2005-11-13 20:18:57 -05:00
if ( i < 0 & & errno ! = ECONNRESET ) {
2022-11-13 12:54:21 -05:00
die ( STATE_CRITICAL , _ ( " HTTP CRITICAL - Error on receive \n " ) ) ;
2005-11-13 20:18:57 -05:00
}
2002-02-28 01:42:51 -05:00
2005-11-13 20:18:57 -05:00
/* return a CRITICAL status if we couldn't read any data */
2022-12-22 05:40:19 -05:00
if ( pagesize = = ( size_t ) 0 )
die ( STATE_CRITICAL , _ ( " HTTP CRITICAL - No data received from host \n " ) ) ;
2002-02-28 01:42:51 -05:00
2005-11-13 20:18:57 -05:00
/* close the connection */
2022-12-22 05:40:19 -05:00
if ( sd ) close ( sd ) ;
2005-10-19 16:22:00 -04:00
# ifdef HAVE_SSL
2005-11-13 20:18:57 -05:00
np_net_ssl_cleanup ( ) ;
2005-10-19 16:22:00 -04:00
# endif
2005-11-13 20:18:57 -05:00
2009-02-03 04:20:29 -05:00
/* Save check time */
2022-12-22 05:40:19 -05:00
microsec = deltime ( tv ) ;
2009-02-03 04:20:29 -05:00
elapsed_time = ( double ) microsec / 1.0e6 ;
2005-11-13 20:18:57 -05:00
/* leave full_page untouched so we can free it later */
page = full_page ;
if ( verbose )
2022-12-22 05:40:19 -05:00
printf ( " %s://%s:%d%s is %d characters \n " ,
use_ssl ? " https " : " http " , server_address ,
server_port , server_url , ( int ) pagesize ) ;
2005-11-13 20:18:57 -05:00
/* find status line and null-terminate it */
status_line = page ;
2022-12-22 05:40:19 -05:00
page + = ( size_t ) strcspn ( page , " \r \n " ) ;
2005-11-13 20:18:57 -05:00
pos = page ;
2022-12-22 05:40:19 -05:00
page + = ( size_t ) strspn ( page , " \r \n " ) ;
2005-11-13 20:18:57 -05:00
status_line [ strcspn ( status_line , " \r \n " ) ] = 0 ;
2022-12-22 05:40:19 -05:00
strip ( status_line ) ;
2005-11-13 20:18:57 -05:00
if ( verbose )
2022-12-22 05:40:19 -05:00
printf ( " STATUS: %s \n " , status_line ) ;
2005-11-13 20:18:57 -05:00
/* find header info and null-terminate it */
header = page ;
2022-12-22 05:40:19 -05:00
while ( strcspn ( page , " \r \n " ) > 0 ) {
page + = ( size_t ) strcspn ( page , " \r \n " ) ;
2005-11-13 20:18:57 -05:00
pos = page ;
2022-12-22 05:40:19 -05:00
if ( ( strspn ( page , " \r " ) = = 1 & & strspn ( page , " \r \n " ) > = 2 ) | |
( strspn ( page , " \n " ) = = 1 & & strspn ( page , " \r \n " ) > = 2 ) )
page + = ( size_t ) 2 ;
2005-11-13 20:18:57 -05:00
else
2022-12-22 05:40:19 -05:00
page + = ( size_t ) 1 ;
2005-11-13 20:18:57 -05:00
}
2022-12-22 05:40:19 -05:00
page + = ( size_t ) strspn ( page , " \r \n " ) ;
2005-11-13 20:18:57 -05:00
header [ pos - header ] = 0 ;
if ( verbose )
2022-12-22 05:40:19 -05:00
printf ( " **** HEADER **** \n %s \n **** CONTENT **** \n %s \n " , header ,
( no_body ? " [[ skipped ]] " : page ) ) ;
2002-02-28 01:42:51 -05:00
2005-11-13 20:18:57 -05:00
/* make sure the status line matches the response we are looking for */
2022-12-22 05:40:19 -05:00
if ( ! expected_statuscode ( status_line , server_expect ) ) {
2005-11-13 20:18:57 -05:00
if ( server_port = = HTTP_PORT )
2022-12-22 05:40:19 -05:00
xasprintf ( & msg ,
_ ( " Invalid HTTP response received from host: %s \n " ) ,
2008-08-25 07:42:57 -04:00
status_line ) ;
2005-11-13 20:18:57 -05:00
else
2022-12-22 05:40:19 -05:00
xasprintf ( & msg ,
2008-08-25 07:42:57 -04:00
_ ( " Invalid HTTP response received from host on port %d: %s \n " ) ,
server_port , status_line ) ;
2019-02-12 07:01:23 -05:00
if ( show_body )
2022-12-22 05:40:19 -05:00
xasprintf ( & msg , _ ( " %s \n %s " ) , msg , page ) ;
die ( STATE_CRITICAL , " HTTP CRITICAL - %s " , msg ) ;
2005-11-13 20:18:57 -05:00
}
2022-12-22 05:40:19 -05: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 */
if ( server_expect_yn ) {
xasprintf ( & msg ,
_ ( " Status line output matched \" %s \" - " ) , server_expect ) ;
2005-11-13 20:18:57 -05:00
if ( verbose )
2022-12-22 05:40:19 -05:00
printf ( " %s \n " , msg ) ;
}
else {
2005-11-13 20:18:57 -05:00
/* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
/* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
2003-09-15 01:03:47 -04:00
/* Status-Code = 3 DIGITS */
2022-12-22 05:40:19 -05:00
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 ) ;
2005-11-13 20:18:57 -05:00
2022-12-22 05:40:19 -05:00
http_status = atoi ( status_code ) ;
2005-11-13 20:18:57 -05:00
/* check the return code */
2009-02-03 04:20:29 -05:00
if ( http_status > = 600 | | http_status < 100 ) {
2022-12-22 05:40:19 -05:00
die ( STATE_CRITICAL , _ ( " HTTP CRITICAL: Invalid Status (%s) \n " ) , status_line ) ;
2009-02-03 04:20:29 -05:00
}
2005-11-13 20:18:57 -05:00
/* server errors result in a critical state */
2009-02-03 04:20:29 -05:00
else if ( http_status > = 500 ) {
2022-12-22 05:40:19 -05:00
xasprintf ( & msg , _ ( " %s - " ) , status_line ) ;
2009-02-03 04:20:29 -05:00
result = STATE_CRITICAL ;
}
2005-11-13 20:18:57 -05:00
/* client errors result in a warning state */
2009-02-03 04:20:29 -05:00
else if ( http_status > = 400 ) {
2022-12-22 05:40:19 -05:00
xasprintf ( & msg , _ ( " %s - " ) , status_line ) ;
2009-02-03 04:20:29 -05:00
result = max_state_alt ( STATE_WARNING , result ) ;
}
2005-11-13 20:18:57 -05:00
/* check redirected page if specified */
else if ( http_status > = 300 ) {
if ( onredirect = = STATE_DEPENDENT )
2022-12-22 05:40:19 -05:00
redir ( header , status_line ) ;
2009-02-03 04:20:29 -05:00
else
result = max_state_alt ( onredirect , result ) ;
2022-12-22 05:40:19 -05:00
xasprintf ( & msg , _ ( " %s - " ) , status_line ) ;
2005-11-13 20:18:57 -05:00
} /* end if (http_status >= 300) */
2009-02-03 04:20:29 -05:00
else {
/* Print OK status anyway */
2022-12-22 05:40:19 -05:00
xasprintf ( & msg , _ ( " %s - " ) , status_line ) ;
2009-02-03 04:20:29 -05:00
}
2005-11-13 20:18:57 -05:00
} /* end else (server_expect_yn) */
2008-04-27 10:35:26 -04:00
2022-12-22 05:40:19 -05:00
/* reset the alarm - must be called *after* redir or we'll never die on redirects! */
alarm ( 0 ) ;
2009-03-19 16:59:43 -04:00
2009-02-03 04:20:29 -05:00
if ( maximum_age > = 0 ) {
result = max_state_alt ( check_document_dates ( header , & msg ) , result ) ;
}
2005-11-13 20:18:57 -05:00
/* Page and Header content checks go here */
2022-11-13 17:06:51 -05:00
if ( strlen ( header_expect ) > 0 ) {
if ( strstr ( header , header_expect ) = = NULL ) {
// We did not find the header, the rest is for building the output and setting the state
char output_header_search [ 30 ] = " " ;
2022-12-22 07:16:19 -05:00
2022-11-13 12:54:21 -05:00
strncpy ( & output_header_search [ 0 ] , header_expect ,
sizeof ( output_header_search ) ) ;
2022-12-22 07:16:19 -05:00
2022-11-13 12:54:21 -05:00
if ( output_header_search [ sizeof ( output_header_search ) - 1 ] ! = ' \0 ' ) {
2022-12-22 07:16:19 -05:00
bcopy ( " ... " ,
& output_header_search [ sizeof ( output_header_search ) - 4 ] ,
4 ) ;
2012-06-07 00:35:34 -04:00
}
2022-12-22 07:16:19 -05:00
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 ) ;
2012-06-07 00:35:34 -04:00
result = STATE_CRITICAL ;
}
}
2022-11-13 17:07:14 -05:00
// At this point we should test if the content is chunked and unchunk it, so
// it can be searched (and possibly printed)
2022-11-13 18:34:13 -05:00
const char * chunked_header_regex_string = " Transfer-Encoding: *chunked * " ;
2022-11-13 17:07:14 -05:00
regex_t chunked_header_regex ;
2022-11-13 18:34:13 -05:00
if ( regcomp ( & chunked_header_regex , chunked_header_regex_string , REG_ICASE ) ) {
2022-11-13 17:07:14 -05:00
die ( STATE_UNKNOWN , " HTTP %s: %s \n " , state_text ( STATE_UNKNOWN ) , " Failed to compile chunked_header_regex regex " ) ;
}
regmatch_t chre_pmatch [ 1 ] ; // We actually do not care about this, since we only want to know IF it was found
2023-08-08 04:22:53 -04:00
if ( ! no_body & & regexec ( & chunked_header_regex , header , 1 , chre_pmatch , 0 ) = = 0 ) {
2022-11-13 18:35:19 -05:00
if ( verbose ) {
printf ( " Found chunked content \n " ) ;
}
2022-11-13 17:07:14 -05:00
// We actually found the chunked header
char * tmp = unchunk_content ( page ) ;
if ( tmp = = NULL ) {
die ( STATE_UNKNOWN , " HTTP %s: %s \n " , state_text ( STATE_UNKNOWN ) , " Failed to unchunk message body " ) ;
}
2022-11-13 18:35:19 -05:00
page = tmp ;
2022-11-13 17:07:14 -05:00
}
if ( strlen ( string_expect ) > 0 ) {
2022-11-13 12:54:21 -05:00
if ( ! strstr ( page , string_expect ) ) {
2022-11-13 17:06:51 -05:00
// We found the string the body, the rest is for building the output
char output_string_search [ 30 ] = " " ;
2022-11-13 12:54:21 -05: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 ) ;
2010-06-23 10:44:34 -04:00
}
2022-12-22 05:40:19 -05: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 ) ;
2009-02-03 04:20:29 -05:00
result = STATE_CRITICAL ;
2005-11-13 20:18:57 -05:00
}
}
2006-05-25 08:33:24 -04:00
2022-11-13 17:06:51 -05:00
if ( strlen ( regexp ) > 0 ) {
2022-11-13 12:54:21 -05:00
errcode = regexec ( & preg , page , REGS , pmatch , 0 ) ;
if ( ( errcode = = 0 & & invert_regex = = 0 ) | |
( errcode = = REG_NOMATCH & & invert_regex = = 1 ) ) {
2009-02-03 04:20:29 -05:00
/* OK - No-op to avoid changing the logic around it */
result = max_state_alt ( STATE_OK , result ) ;
2022-12-22 05:40:19 -05:00
}
else if ( ( errcode = = REG_NOMATCH & & invert_regex = = 0 ) | | ( errcode = = 0 & & invert_regex = = 1 ) ) {
2008-11-19 01:45:18 -05:00
if ( invert_regex = = 0 )
2022-12-22 05:40:19 -05:00
xasprintf ( & msg , _ ( " %spattern not found, " ) , msg ) ;
2008-11-19 01:45:18 -05:00
else
2022-12-22 05:40:19 -05:00
xasprintf ( & msg , _ ( " %spattern found, " ) , msg ) ;
2024-04-07 14:01:54 -04:00
result = state_regex ;
2022-12-22 05:40:19 -05:00
}
else {
2009-02-03 04:20:29 -05:00
/* FIXME: Shouldn't that be UNKNOWN? */
2022-12-22 05:40:19 -05:00
regerror ( errcode , & preg , errbuf , MAX_INPUT_BUFFER ) ;
xasprintf ( & msg , _ ( " %sExecute Error: %s, " ) , msg , errbuf ) ;
2009-02-03 04:20:29 -05:00
result = STATE_CRITICAL ;
2005-11-13 20:18:57 -05:00
}
}
2002-02-28 01:42:51 -05:00
2005-11-13 20:18:57 -05:00
/* make sure the page is of an appropriate size */
/* page_len = get_content_length(header); */
2009-02-03 04:20:29 -05: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 ) ? ?
*/
2005-11-13 20:18:57 -05:00
page_len = pagesize ;
if ( ( max_page_len > 0 ) & & ( page_len > max_page_len ) ) {
2022-12-22 05:40:19 -05:00
xasprintf ( & msg , _ ( " %spage size %d too large, " ) , msg , page_len ) ;
2009-02-03 04:20:29 -05:00
result = max_state_alt ( STATE_WARNING , result ) ;
2005-11-13 20:18:57 -05:00
} else if ( ( min_page_len > 0 ) & & ( page_len < min_page_len ) ) {
2022-12-22 05:40:19 -05:00
xasprintf ( & msg , _ ( " %spage size %d too small, " ) , msg , page_len ) ;
2009-02-03 04:20:29 -05:00
result = max_state_alt ( STATE_WARNING , result ) ;
2005-11-13 20:18:57 -05:00
}
2009-02-03 04:20:29 -05:00
/* Cut-off trailing characters */
2022-12-22 05:40:19 -05:00
if ( msg [ strlen ( msg ) - 2 ] = = ' , ' )
msg [ strlen ( msg ) - 2 ] = ' \0 ' ;
2009-02-03 04:20:29 -05:00
else
2022-12-22 05:40:19 -05:00
msg [ strlen ( msg ) - 3 ] = ' \0 ' ;
2009-02-03 04:20:29 -05:00
/* check elapsed time */
2013-05-19 05:36:06 -04:00
if ( show_extended_perfdata )
2022-12-22 05:40:19 -05:00
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 ) ) ;
2013-05-19 05:36:06 -04:00
else
2022-12-22 05:40:19 -05:00
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-08-15 11:28:49 -04:00
2018-11-09 17:48:56 -05:00
if ( show_body )
2022-12-22 05:40:19 -05:00
xasprintf ( & msg , _ ( " %s \n %s " ) , msg , page ) ;
2018-11-09 17:48:56 -05:00
2011-01-01 15:29:43 -05:00
result = max_state_alt ( get_status ( elapsed_time , thlds ) , result ) ;
2009-02-03 04:20:29 -05:00
2022-12-22 05:40:19 -05:00
die ( result , " HTTP %s: %s \n " , state_text ( result ) , msg ) ;
2009-02-03 04:20:29 -05:00
/* die failed? */
2005-11-13 20:18:57 -05:00
return STATE_UNKNOWN ;
2002-02-28 01:42:51 -05:00
}
2002-06-24 17:29:06 -04:00
2022-11-13 17:07:14 -05:00
/* Receivces a pointer to the beginning of the body of a HTTP message
* which is chunked and returns a pointer to a freshly allocated memory
* region containing the unchunked body or NULL if something failed .
* The result must be freed by the caller .
*/
char * unchunk_content ( const char * content ) {
// https://en.wikipedia.org/wiki/Chunked_transfer_encoding
// https://www.rfc-editor.org/rfc/rfc7230#section-4.1
char * result = NULL ;
2022-11-13 18:35:19 -05:00
char * start_of_chunk ;
char * end_of_chunk ;
2022-11-13 17:07:14 -05:00
long size_of_chunk ;
2022-11-13 18:35:19 -05:00
const char * pointer = content ;
2022-11-13 17:07:14 -05:00
char * endptr ;
long length_of_chunk = 0 ;
size_t overall_size = 0 ;
while ( true ) {
size_of_chunk = strtol ( pointer , & endptr , 16 ) ;
if ( size_of_chunk = = LONG_MIN | | size_of_chunk = = LONG_MAX ) {
// Apparently underflow or overflow, should not happen
if ( verbose ) {
printf ( " Got an underflow or overflow from strtol at: %u \n " , __LINE__ ) ;
}
return NULL ;
}
if ( endptr = = pointer ) {
// Apparently this was not a number
if ( verbose ) {
printf ( " Chunked content did not start with a number at all (Line: %u) \n " , __LINE__ ) ;
}
2022-11-13 18:35:19 -05:00
return NULL ;
2022-11-13 17:07:14 -05:00
}
// So, we got the length of the chunk
if ( * endptr = = ' ; ' ) {
// Chunk extension starts here
while ( * endptr ! = ' \r ' ) {
endptr + + ;
}
}
start_of_chunk = endptr + 2 ;
end_of_chunk = start_of_chunk + size_of_chunk ;
2022-11-13 18:35:19 -05:00
length_of_chunk = ( long ) ( end_of_chunk - start_of_chunk ) ;
pointer = end_of_chunk + 2 ; //Next number should be here
2022-11-13 17:07:14 -05:00
if ( length_of_chunk = = 0 ) {
// Chunk length is 0, so this is the last one
break ;
}
overall_size + = length_of_chunk ;
if ( result = = NULL ) {
2023-01-30 07:33:46 -05:00
// Size of the chunk plus the ending NULL byte
result = ( char * ) malloc ( length_of_chunk + 1 ) ;
2022-11-13 17:07:14 -05:00
if ( result = = NULL ) {
if ( verbose ) {
printf ( " Failed to allocate memory for unchunked body \n " ) ;
}
return NULL ;
}
} else {
2023-01-30 07:33:46 -05:00
// Enlarge memory to the new size plus the ending NULL byte
void * tmp = realloc ( result , overall_size + 1 ) ;
2022-11-13 17:07:14 -05:00
if ( tmp = = NULL ) {
if ( verbose ) {
printf ( " Failed to allocate memory for unchunked body \n " ) ;
}
return NULL ;
2023-01-30 06:45:20 -05:00
} else {
result = tmp ;
2022-11-13 17:07:14 -05:00
}
}
2023-01-30 06:45:20 -05:00
memcpy ( result + ( overall_size - size_of_chunk ) , start_of_chunk , size_of_chunk ) ;
2022-11-13 17:07:14 -05:00
}
2023-02-06 05:39:44 -05:00
if ( overall_size = = 0 & & result = = NULL ) {
// We might just have received the end chunk without previous content, so result is never allocated
result = calloc ( 1 , sizeof ( char ) ) ;
// No error handling here, we can only return NULL anyway
} else {
result [ overall_size ] = ' \0 ' ;
}
2022-11-13 18:35:19 -05:00
return result ;
2022-11-13 17:07:14 -05:00
}
2003-08-21 14:00:48 -04:00
/* per RFC 2396 */
2007-06-17 15:22:51 -04:00
# define URI_HTTP "%5[HTPShtps]"
2022-12-22 05:40:19 -05:00
# define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
2007-06-17 15:22:51 -04:00
# define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
2022-12-22 05:40:19 -05:00
# define URI_PATH "%[-_.!~*'(); / ?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
2007-06-17 15:22:51 -04: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
2022-12-22 05:40:19 -05:00
/* relative reference redirect like //www.site.org/test https://tools.ietf.org/html/rfc3986 */
2016-11-21 16:40:39 -05:00
# define HD5 " //" URI_HOST "/" URI_PATH
2016-12-31 07:57:44 -05:00
# define HD6 URI_PATH
2003-08-21 14:00:48 -04:00
2022-12-22 05:40:19 -05:00
void
redir ( char * pos , char * status_line )
{
2005-11-13 20:18:57 -05:00
int i = 0 ;
char * x ;
char xx [ 2 ] ;
char type [ 6 ] ;
char * addr ;
char * url ;
2022-12-22 05:40:19 -05:00
addr = malloc ( MAX_IPV4_HOSTLENGTH + 1 ) ;
2005-11-13 20:18:57 -05:00
if ( addr = = NULL )
2022-12-22 05:40:19 -05:00
die ( STATE_UNKNOWN , _ ( " HTTP UNKNOWN - Could not allocate addr \n " ) ) ;
2008-04-27 10:35:26 -04:00
2014-06-22 16:34:25 -04:00
memset ( addr , 0 , MAX_IPV4_HOSTLENGTH ) ;
2022-12-22 05:40:19 -05:00
url = malloc ( strcspn ( pos , " \r \n " ) ) ;
2005-11-13 20:18:57 -05:00
if ( url = = NULL )
2022-12-22 05:40:19 -05:00
die ( STATE_UNKNOWN , _ ( " HTTP UNKNOWN - Could not allocate URL \n " ) ) ;
2005-11-13 20:18:57 -05:00
while ( pos ) {
2022-12-22 05:40:19 -05:00
sscanf ( pos , " %1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n " , xx , & i ) ;
2006-10-24 04:34:31 -04:00
if ( i = = 0 ) {
2022-12-22 05:40:19 -05:00
pos + = ( size_t ) strcspn ( pos , " \r \n " ) ;
pos + = ( size_t ) strspn ( pos , " \r \n " ) ;
2008-11-19 01:45:18 -05:00
if ( strlen ( pos ) = = 0 )
2022-12-22 05:40:19 -05:00
die ( STATE_UNKNOWN ,
_ ( " HTTP UNKNOWN - Could not find redirect location - %s%s \n " ) ,
status_line , ( display_html ? " </A> " : " " ) ) ;
2005-11-13 20:18:57 -05:00
continue ;
}
pos + = i ;
2022-12-22 05:40:19 -05:00
pos + = strspn ( pos , " \t " ) ;
2007-06-15 14:37:13 -04: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 . ' '
*/
2022-12-22 05:40:19 -05:00
for ( ; ( i = strspn ( pos , " \r \n " ) ) ; pos + = i ) {
2007-06-15 14:37:13 -04:00
pos + = i ;
2022-12-22 05:40:19 -05:00
if ( ! ( i = strspn ( pos , " \t " ) ) ) {
die ( STATE_UNKNOWN , _ ( " HTTP UNKNOWN - Empty redirect location%s \n " ) ,
display_html ? " </A> " : " " ) ;
2007-06-15 14:37:13 -04:00
}
}
2005-11-13 20:18:57 -05:00
2022-12-22 05:40:19 -05:00
url = realloc ( url , strcspn ( pos , " \r \n " ) + 1 ) ;
2005-11-13 20:18:57 -05:00
if ( url = = NULL )
2022-12-22 05:40:19 -05:00
die ( STATE_UNKNOWN , _ ( " HTTP UNKNOWN - Could not allocate URL \n " ) ) ;
2005-11-13 20:18:57 -05:00
/* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
2022-12-22 05:40:19 -05:00
if ( sscanf ( pos , HD1 , type , addr , & i , url ) = = 4 ) {
url = prepend_slash ( url ) ;
use_ssl = server_type_check ( type ) ;
2008-09-01 08:20:32 -04:00
}
2005-11-13 20:18:57 -05:00
/* URI_HTTP URI_HOST URI_PATH */
2022-12-22 05:40:19 -05:00
else if ( sscanf ( pos , HD2 , type , addr , url ) = = 3 ) {
url = prepend_slash ( url ) ;
use_ssl = server_type_check ( type ) ;
i = server_port_check ( use_ssl ) ;
2005-11-13 20:18:57 -05:00
}
/* URI_HTTP URI_HOST URI_PORT */
2022-12-22 05:40:19 -05:00
else if ( sscanf ( pos , HD3 , type , addr , & i ) = = 3 ) {
strcpy ( url , HTTP_URL ) ;
use_ssl = server_type_check ( type ) ;
2005-11-13 20:18:57 -05:00
}
/* URI_HTTP URI_HOST */
2022-12-22 05:40:19 -05:00
else if ( sscanf ( pos , HD4 , type , addr ) = = 2 ) {
strcpy ( url , HTTP_URL ) ;
use_ssl = server_type_check ( type ) ;
i = server_port_check ( use_ssl ) ;
2005-11-13 20:18:57 -05:00
}
2016-11-21 16:40:39 -05:00
/* URI_HTTP, URI_HOST, URI_PATH */
2022-12-22 05:40:19 -05:00
else if ( sscanf ( pos , HD5 , addr , url ) = = 2 ) {
if ( use_ssl ) {
strcpy ( type , " https " ) ;
2016-04-11 13:52:02 -04:00
}
2022-12-22 05:40:19 -05:00
else {
strcpy ( type , server_type ) ;
}
xasprintf ( & url , " /%s " , url ) ;
use_ssl = server_type_check ( type ) ;
i = server_port_check ( use_ssl ) ;
2016-04-11 13:52:02 -04:00
}
2005-11-13 20:18:57 -05:00
/* URI_PATH */
2022-12-22 05:40:19 -05:00
else if ( sscanf ( pos , HD6 , url ) = = 1 ) {
2005-11-13 20:18:57 -05:00
/* relative url */
if ( ( url [ 0 ] ! = ' / ' ) ) {
if ( ( x = strrchr ( server_url , ' / ' ) ) )
* x = ' \0 ' ;
2022-12-22 05:40:19 -05:00
xasprintf ( & url , " %s/%s " , server_url , url ) ;
2005-11-13 20:18:57 -05:00
}
i = server_port ;
2022-12-22 05:40:19 -05:00
strcpy ( type , server_type ) ;
strcpy ( addr , host_name ? host_name : server_address ) ;
2008-11-19 01:45:18 -05:00
}
2005-11-13 20:18:57 -05:00
else {
2022-12-22 05:40:19 -05:00
die ( STATE_UNKNOWN ,
_ ( " HTTP UNKNOWN - Could not parse redirect location - %s%s \n " ) ,
pos , ( display_html ? " </A> " : " " ) ) ;
2005-11-13 20:18:57 -05:00
}
break ;
} /* end while (pos) */
if ( + + redir_depth > max_depth )
2022-12-22 05:40:19 -05:00
die ( STATE_WARNING ,
_ ( " HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s \n " ) ,
max_depth , type , addr , i , url , ( display_html ? " </A> " : " " ) ) ;
2005-11-13 20:18:57 -05:00
2022-12-22 05:40:19 -05:00
if ( server_port = = i & &
! strncmp ( server_address , addr , MAX_IPV4_HOSTLENGTH ) & &
2014-06-22 16:34:25 -04:00
( host_name & & ! strncmp ( host_name , addr , MAX_IPV4_HOSTLENGTH ) ) & &
2005-11-13 20:18:57 -05:00
! strcmp ( server_url , url ) )
2022-12-22 05:40:19 -05:00
die ( STATE_CRITICAL ,
_ ( " HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s \n " ) ,
type , addr , i , url , ( display_html ? " </A> " : " " ) ) ;
2005-11-13 20:18:57 -05:00
2022-12-22 05:40:19 -05:00
strcpy ( server_type , type ) ;
2005-11-13 20:18:57 -05:00
2022-12-22 05:40:19 -05:00
free ( host_name ) ;
host_name = strndup ( addr , MAX_IPV4_HOSTLENGTH ) ;
2005-11-13 20:18:57 -05:00
2009-03-21 02:32:50 -04:00
if ( ! ( followsticky & STICKY_HOST ) ) {
2022-12-22 05:40:19 -05:00
free ( server_address ) ;
server_address = strndup ( addr , MAX_IPV4_HOSTLENGTH ) ;
2009-02-05 00:08:54 -05:00
}
2009-03-21 02:32:50 -04:00
if ( ! ( followsticky & STICKY_PORT ) ) {
server_port = i ;
}
2005-11-13 20:18:57 -05:00
2022-12-22 05:40:19 -05:00
free ( server_url ) ;
2008-09-01 08:20:32 -04:00
server_url = url ;
2007-06-17 15:22:51 -04:00
2009-03-21 02:32:50 -04:00
if ( server_port > MAX_PORT )
2022-12-22 05:40:19 -05: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> " : " " ) ;
2007-06-17 15:22:51 -04:00
2015-09-15 08:52:18 -04:00
/* reset virtual port */
virtual_port = server_port ;
2007-06-17 15:22:51 -04:00
if ( verbose )
2022-12-22 05:40:19 -05:00
printf ( _ ( " Redirection to %s://%s:%d%s \n " ) , server_type ,
host_name ? host_name : server_address , server_port , server_url ) ;
2005-11-13 20:18:57 -05:00
2014-06-22 16:34:25 -04:00
free ( addr ) ;
2022-12-22 05:40:19 -05:00
check_http ( ) ;
2003-08-21 14:00:48 -04:00
}
2022-12-22 05:40:19 -05:00
bool
server_type_check ( const char * type )
{
if ( strcmp ( type , " https " ) )
2022-11-13 08:47:29 -05:00
return false ;
2005-11-13 20:18:57 -05:00
else
2022-11-13 08:47:29 -05:00
return true ;
2003-08-21 14:00:48 -04:00
}
2022-12-22 05:40:19 -05:00
int
server_port_check ( int ssl_flag )
{
2005-11-13 20:18:57 -05:00
if ( ssl_flag )
return HTTPS_PORT ;
else
return HTTP_PORT ;
2003-08-21 14:00:48 -04:00
}
2022-12-22 05:40:19 -05:00
char * perfd_time ( double elapsed_time )
{
return fperfdata ( " time " , elapsed_time , " s " ,
thlds - > warning ? true : false , thlds - > warning ? thlds - > warning - > end : 0 ,
thlds - > critical ? true : false , thlds - > critical ? thlds - > critical - > end : 0 ,
true , 0 , true , socket_timeout ) ;
2003-09-11 04:02:31 -04:00
}
2022-12-22 05:40:19 -05:00
char * perfd_time_connect ( double elapsed_time_connect )
{
return fperfdata ( " time_connect " , elapsed_time_connect , " s " , false , 0 , false , 0 , false , 0 , true , socket_timeout ) ;
2013-05-19 05:36:06 -04:00
}
2022-12-22 05:40:19 -05:00
char * perfd_time_ssl ( double elapsed_time_ssl )
{
return fperfdata ( " time_ssl " , elapsed_time_ssl , " s " , false , 0 , false , 0 , false , 0 , true , socket_timeout ) ;
2013-05-19 05:36:06 -04:00
}
2003-09-11 07:50:45 -04:00
2022-12-22 05:40:19 -05:00
char * perfd_time_headers ( double elapsed_time_headers )
{
return fperfdata ( " time_headers " , elapsed_time_headers , " s " , false , 0 , false , 0 , false , 0 , true , socket_timeout ) ;
2013-05-19 05:36:06 -04:00
}
2013-08-15 11:28:49 -04:00
2022-12-22 05:40:19 -05:00
char * perfd_time_firstbyte ( double elapsed_time_firstbyte )
{
return fperfdata ( " time_firstbyte " , elapsed_time_firstbyte , " s " , false , 0 , false , 0 , false , 0 , true , socket_timeout ) ;
2013-05-19 05:36:06 -04:00
}
2022-12-22 05:40:19 -05:00
char * perfd_time_transfer ( double elapsed_time_transfer )
{
return fperfdata ( " time_transfer " , elapsed_time_transfer , " s " , false , 0 , false , 0 , false , 0 , true , socket_timeout ) ;
2013-05-19 05:36:06 -04:00
}
2004-12-01 18:54:51 -05:00
2022-12-22 05:40:19 -05: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 ) ;
2003-09-11 07:50:45 -04:00
}
2022-12-22 05:40:19 -05:00
void
print_help ( void )
{
print_revision ( progname , NP_VERSION ) ;
2003-08-08 20:56:03 -04:00
2022-12-22 05:40:19 -05:00
printf ( " Copyright (c) 1999 Ethan Galstad <nagios@nagios.org> \n " ) ;
printf ( COPYRIGHT , copyright , email ) ;
2003-08-08 20:56:03 -04:00
2022-12-22 05:40:19 -05:00
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. " ) ) ;
2005-11-13 20:18:57 -05:00
2022-12-22 05:40:19 -05:00
printf ( " \n \n " ) ;
2005-11-13 20:18:57 -05:00
2022-12-22 05:40:19 -05:00
print_usage ( ) ;
2003-08-08 20:56:03 -04:00
2018-10-09 18:40:07 -04:00
# ifdef HAVE_SSL
2022-12-22 05:40:19 -05:00
printf ( _ ( " In the first form, make an HTTP request. " ) ) ;
printf ( _ ( " In the second form, connect to the server and check the TLS certificate. " ) ) ;
2018-10-09 18:40:07 -04:00
# endif
2022-12-22 05:40:19 -05:00
printf ( _ ( " NOTE: One or both of -H and -I must be specified " ) ) ;
2003-08-08 20:56:03 -04:00
2022-12-22 05:40:19 -05:00
printf ( " \n " ) ;
2003-08-08 20:56:03 -04:00
2022-12-22 05:40:19 -05:00
printf ( UT_HELP_VRSN ) ;
printf ( UT_EXTRA_OPTS ) ;
2003-08-08 20:56:03 -04:00
2022-12-22 05:40:19 -05: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 " ) ;
printf ( " %s " , _ ( " Port number (default: " ) ) ;
printf ( " %d) \n " , HTTP_PORT ) ;
2003-08-08 20:56:03 -04:00
2022-12-22 05:40:19 -05:00
printf ( UT_IPv46 ) ;
2003-08-08 20:56:03 -04:00
# ifdef HAVE_SSL
2022-12-22 05:40:19 -05:00
printf ( " %s \n " , " -S, --ssl=VERSION[+] " ) ;
printf ( " %s \n " , _ ( " Connect via SSL. Port defaults to 443. VERSION is optional, and prevents " ) ) ;
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. " ) ) ;
printf ( " %s \n " , " --sni " ) ;
printf ( " %s \n " , _ ( " Enable SSL/TLS hostname extension support (SNI) " ) ) ;
printf ( " %s \n " , " -C, --certificate=INTEGER[,INTEGER] " ) ;
printf ( " %s \n " , _ ( " Minimum number of days a certificate has to be valid. Port defaults to 443 " ) ) ;
printf ( " %s \n " , _ ( " (when this option is used the URL is not checked by default. You can use " ) ) ;
printf ( " %s \n " , _ ( " --continue-after-certificate to override this behavior) " ) ) ;
printf ( " %s \n " , " --continue-after-certificate " ) ;
printf ( " %s \n " , _ ( " Allows the HTTP check to continue after performing the certificate check. " ) ) ;
printf ( " %s \n " , _ ( " Does nothing unless -C is used. " ) ) ;
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 " ) ) ;
2003-08-08 20:56:03 -04:00
# endif
2022-12-22 05:40:19 -05:00
printf ( " %s \n " , " -e, --expect=STRING " ) ;
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: " ) ) ;
printf ( " %s) \n " , HTTP_EXPECT ) ;
printf ( " %s \n " , _ ( " If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing) " ) ) ;
printf ( " %s \n " , " -d, --header-string=STRING " ) ;
printf ( " %s \n " , _ ( " String to expect in the response headers " ) ) ;
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: /) " ) ) ;
printf ( " %s \n " , " -P, --post=STRING " ) ;
2024-04-07 13:30:26 -04:00
printf ( " %s \n " , _ ( " URL decoded http POST data " ) ) ;
2022-12-22 05:40:19 -05:00
printf ( " %s \n " , " -j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT, CONNECT:POST) " ) ;
printf ( " %s \n " , _ ( " Set HTTP method. " ) ) ;
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 " ) ;
2024-04-07 14:01:54 -04:00
printf ( " %s \n " , _ ( " Return STATE if found, OK if not (STATE is CRITICAL, per default) " ) ) ;
printf ( " %s \n " , _ ( " can be changed with --state--regex) " ) ) ;
printf ( " %s \n " , " --regex-state=STATE " ) ;
printf ( " %s \n " , _ ( " Return STATE if regex is found, OK if not \n " ) ) ;
2022-12-22 05:40:19 -05:00
printf ( " %s \n " , " -a, --authorization=AUTH_PAIR " ) ;
printf ( " %s \n " , _ ( " Username:password on sites with basic authentication " ) ) ;
printf ( " %s \n " , " -b, --proxy-authorization=AUTH_PAIR " ) ;
printf ( " %s \n " , _ ( " Username:password on proxy-servers with basic authentication " ) ) ;
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 " ) ;
printf ( " %s \n " , _ ( " Any other tags to be sent in http header. Use multiple times for additional headers " ) ) ;
printf ( " %s \n " , " -E, --extended-perfdata " ) ;
printf ( " %s \n " , _ ( " Print additional performance data " ) ) ;
printf ( " %s \n " , " -B, --show-body " ) ;
printf ( " %s \n " , _ ( " Print body content below status line " ) ) ;
printf ( " %s \n " , " -L, --link " ) ;
printf ( " %s \n " , _ ( " Wrap output in HTML link (obsoleted by urlize) " ) ) ;
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 " ) ) ;
printf ( " %s \n " , _ ( " specified IP address. stickyport also ensures port stays the same. " ) ) ;
printf ( " %s \n " , " --max-redirs=INTEGER " ) ;
printf ( " %s " , _ ( " Maximal number of redirects (default: " ) ) ;
printf ( " %d) \n " , DEFAULT_MAX_REDIRS ) ;
printf ( " %s \n " , " -m, --pagesize=INTEGER<:INTEGER> " ) ;
printf ( " %s \n " , _ ( " Minimum page size required (bytes) : Maximum page size required (bytes) " ) ) ;
printf ( UT_WARN_CRIT ) ;
printf ( UT_CONN_TIMEOUT , DEFAULT_SOCKET_TIMEOUT ) ;
printf ( UT_VERBOSE ) ;
printf ( " \n " ) ;
printf ( " %s \n " , _ ( " Notes: " ) ) ;
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 " ) ) ;
printf ( " %s \n " , _ ( " other errors return STATE_UNKNOWN. Successful connects, but incorrect response " ) ) ;
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. " ) ) ;
2003-08-08 20:56:03 -04:00
# ifdef HAVE_SSL
2022-12-22 05:40:19 -05:00
printf ( " \n " ) ;
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. " ) ) ;
printf ( " \n " ) ;
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 " ) ;
printf ( " %s \n " , _ ( " Examples: " ) ) ;
printf ( " %s \n \n " , " CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com " ) ;
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, " ) ) ;
printf ( " %s \n " , _ ( " a STATE_CRITICAL will be returned. " ) ) ;
printf ( " \n " ) ;
printf ( " %s \n \n " , " CHECK CERTIFICATE: check_http -H www.verisign.com -C 14 " ) ;
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 " ) ) ;
printf ( " %s \n \n " , _ ( " the certificate is expired. " ) ) ;
printf ( " \n " ) ;
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 " ) ) ;
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, " ) ) ;
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 " ) ) ;
2015-08-27 11:09:15 -04:00
2003-08-08 20:56:03 -04:00
# endif
2022-12-22 05:40:19 -05:00
printf ( UT_SUPPORT ) ;
2003-08-08 20:56:03 -04:00
}
2022-12-22 05:40:19 -05:00
void
print_usage ( void )
{
printf ( " %s \n " , _ ( " Usage: " ) ) ;
printf ( " %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>] \n " , progname ) ;
printf ( " [-J <client certificate file>] [-K <private key>] \n " ) ;
printf ( " [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth] \n " ) ;
2023-04-14 10:37:47 -04:00
printf ( " [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport>] \n " ) ;
2022-12-22 05:40:19 -05:00
printf ( " [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] \n " ) ;
printf ( " [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] \n " ) ;
printf ( " [-A string] [-k string] [-S <version>] [--sni] \n " ) ;
printf ( " [-T <content-type>] [-j method] \n " ) ;
printf ( " %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>] \n " , progname ) ;
printf ( " [-p <port>] [-t <timeout>] [-4|-6] [--sni] \n " ) ;
2003-08-08 20:56:03 -04:00
}